Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41b669a35c | ||
|
|
7b5ca3bc57 | ||
|
|
bb0c7fd22b | ||
|
|
c79958541e | ||
|
|
94ee8863d6 | ||
|
|
011477262d | ||
|
|
2e8e4cefb0 | ||
|
|
5e2802c098 | ||
|
|
9a6250a055 | ||
|
|
f8cb56525a | ||
|
|
b5b491cb7b | ||
|
|
7eb6be70f9 | ||
|
|
0de8a5fabc | ||
|
|
9fbc18fb70 | ||
|
|
e7ce3368b0 | ||
|
|
729600e9c6 | ||
|
|
54886f385b |
No files matched your search
@@ -0,0 +1,126 @@
|
||||
name: Dev
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
docker-build:
|
||||
if: github.repository == 'devlikeapro/waha-plus'
|
||||
runs-on: ${{ matrix.runner }}
|
||||
name:
|
||||
${{ matrix.engine }} - ${{ matrix.browser }} - ${{ matrix.platform }} -
|
||||
${{ matrix.tag }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- runner: 'buildjet-4vcpu-ubuntu-2204'
|
||||
tag: 'dev'
|
||||
platform: 'amd64'
|
||||
browser: 'chromium'
|
||||
engine: 'WEBJS'
|
||||
goss: 'goss-linux-amd64'
|
||||
- runner: 'buildjet-4vcpu-ubuntu-2204-arm'
|
||||
tag: 'dev-arm'
|
||||
platform: 'linux/arm64'
|
||||
browser: 'chromium'
|
||||
engine: 'WEBJS'
|
||||
goss: 'goss-linux-arm'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check recent changes
|
||||
id: recent
|
||||
run: |
|
||||
count=$(git rev-list --after="24 hours ago" --count HEAD || true)
|
||||
if [ "$count" -gt 0 ]; then
|
||||
echo "has_recent=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "has_recent=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: No recent changes summary
|
||||
if: ${{ steps.recent.outputs.has_recent != 'true' }}
|
||||
run:
|
||||
echo "No commits in the last 24 hours; skipping build." >>
|
||||
"$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Docker meta
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ vars.DOCKER_IMAGE }}
|
||||
flavor: latest=false
|
||||
tags: |
|
||||
type=raw,value=${{ matrix.tag }}
|
||||
|
||||
- name: Login to image repository
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
USE_BROWSER=${{ matrix.browser }}
|
||||
WHATSAPP_DEFAULT_ENGINE=${{ matrix.engine }}
|
||||
push: false
|
||||
load: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Install goss
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
env:
|
||||
GOSS_DOWNLOAD: 'https://github.com/goss-org/goss/releases/download'
|
||||
GOSS_VERSION: 'v0.4.8'
|
||||
run: |
|
||||
curl -L https://github.com/goss-org/goss/releases/download/${{ env.GOSS_VERSION }}/${{ matrix.goss }} -o /usr/local/bin/goss
|
||||
chmod +rx /usr/local/bin/goss
|
||||
|
||||
- name: Run smoke tests
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
working-directory: tests/smoke
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
docker run -d \
|
||||
--name smoke \
|
||||
--rm -p3000:3000 \
|
||||
-e WAHA_API_KEY=test \
|
||||
${{ vars.DOCKER_IMAGE }}:${{ matrix.tag }}
|
||||
|
||||
sleep 3
|
||||
docker logs smoke
|
||||
goss validate --retry-timeout 30s --sleep 1s
|
||||
docker rm --force smoke
|
||||
|
||||
- name: Push
|
||||
if: ${{ steps.recent.outputs.has_recent == 'true' }}
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
build-args: |
|
||||
USE_BROWSER=${{ matrix.browser }}
|
||||
WHATSAPP_DEFAULT_ENGINE=${{ matrix.engine }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
@@ -15,6 +15,7 @@ on:
|
||||
|
||||
jobs:
|
||||
en:
|
||||
if: github.repository == 'devlikeapro/waha'
|
||||
permissions:
|
||||
issues: write
|
||||
discussions: write
|
||||
@@ -31,21 +32,20 @@ jobs:
|
||||
CUSTOM_BOT_NOTE: 'English'
|
||||
TARGET_LANGUAGE: 'eng'
|
||||
TRANSLATED_LANGUAGE: 'en'
|
||||
|
||||
pt:
|
||||
permissions:
|
||||
issues: write
|
||||
discussions: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: devlikeapro/github-translate-action@main
|
||||
env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
IS_MODIFY_TITLE: false
|
||||
CUSTOM_BOT_NOTE: 'Portuguese'
|
||||
TARGET_LANGUAGE: 'por'
|
||||
TRANSLATED_LANGUAGE: 'pt'
|
||||
# pt:
|
||||
# permissions:
|
||||
# issues: write
|
||||
# discussions: write
|
||||
# pull-requests: write
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: devlikeapro/github-translate-action@main
|
||||
# env:
|
||||
# # GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# with:
|
||||
# IS_MODIFY_TITLE: false
|
||||
# CUSTOM_BOT_NOTE: 'Portuguese'
|
||||
# TARGET_LANGUAGE: 'por'
|
||||
# TRANSLATED_LANGUAGE: 'pt'
|
||||
@@ -35,7 +35,7 @@ for-swagger:
|
||||
WHATSAPP_SWAGGER_CONFIG_ADVANCED=true . ${NVM_DIR}/nvm.sh && nvm exec yarn start
|
||||
|
||||
up-noweb:
|
||||
yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-10-10
|
||||
yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-10-19
|
||||
|
||||
up-noweb-libsignal:
|
||||
yarn up libsignal@github:devlikeapro/libsignal-node#fork-master
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
@@ -26,7 +26,7 @@
|
||||
"gows:proto": "yarn gows:proto:fetch && yarn gows:proto:build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-10-10",
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-10-19",
|
||||
"@adiwajshing/keyed-db": "^0.2.4",
|
||||
"@aws-sdk/client-s3": "^3.633.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.633.0",
|
||||
|
||||
@@ -13,13 +13,11 @@ import { Locale } from '@waha/apps/chatwoot/i18n/locale';
|
||||
import { WAHASessionAPI } from '@waha/apps/chatwoot/session/WAHASelf';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
|
||||
import { WAHAEvents, WAMessageAck } from '@waha/structures/enums.dto';
|
||||
import { WAHAEvents } from '@waha/structures/enums.dto';
|
||||
import { WAHAWebhookMessageAck } from '@waha/structures/webhooks.dto';
|
||||
import { Job } from 'bullmq';
|
||||
import { PinoLogger } from 'nestjs-pino';
|
||||
import { isJidCusFormat } from '@waha/utils/wa';
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import { toCusFormat } from '@waha/core/utils/jids';
|
||||
import { ShouldMarkAsReadInChatWoot } from '@waha/apps/chatwoot/consumers/waha/message.ack.utils';
|
||||
|
||||
@Processor(QueueName.WAHA_MESSAGE_ACK, { concurrency: JOB_CONCURRENCY })
|
||||
export class WAHAMessageAckConsumer extends ChatWootWAHABaseConsumer {
|
||||
@@ -31,30 +29,8 @@ export class WAHAMessageAckConsumer extends ChatWootWAHABaseConsumer {
|
||||
super(manager, log, rmutex, 'WAHAMessageAckConsumer');
|
||||
}
|
||||
|
||||
ShouldProcess(event: WAHAWebhookMessageAck): boolean {
|
||||
// Mark as seen only if it's DM
|
||||
// Ignore groups and other multiple participants chats
|
||||
const chatId = this.GetChatId(event);
|
||||
if (!isJidCusFormat(chatId) && !isLidUser(chatId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const payload = event.payload;
|
||||
// Only READ and PLAYED
|
||||
const read = payload.ack === WAMessageAck.READ;
|
||||
const played = payload.ack == WAMessageAck.PLAYED;
|
||||
if (!read && !played) {
|
||||
return true;
|
||||
}
|
||||
// Only not from me
|
||||
const sender = toCusFormat(payload._data?.Sender) || payload.from;
|
||||
const me = this.manager.getSession(event.session).getSessionMeInfo();
|
||||
if (sender == me.id || sender === me.lid) {
|
||||
this.logger.debug('Ignore from me ack');
|
||||
// Ignore from me
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
ShouldProcess(event: any): boolean {
|
||||
return ShouldMarkAsReadInChatWoot(event);
|
||||
}
|
||||
|
||||
GetChatId(event: WAHAWebhookMessageAck): string {
|
||||
|
||||
@@ -0,0 +1,466 @@
|
||||
import type { WAHAEngine, WAHAEvents } from '@waha/structures/enums.dto';
|
||||
import { ShouldMarkAsReadInChatWoot } from '@waha/apps/chatwoot/consumers/waha/message.ack.utils';
|
||||
|
||||
interface TestParam {
|
||||
name: string;
|
||||
expected: boolean;
|
||||
GOWS: any;
|
||||
NOWEB: any;
|
||||
WEBJS: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Me - 444444444444 (lid - 144444444444444)
|
||||
* Participant - 11111111111 (lid - 011111111111111)
|
||||
* Group - 222222222222222222
|
||||
*/
|
||||
const ShouldMarkAsReadCases: TestParam[] = [
|
||||
{
|
||||
name: 'Participant read My message (READ ack)',
|
||||
expected: true,
|
||||
GOWS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack' as WAHAEvents,
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_3333333333333333333333',
|
||||
from: '11111111111@c.us',
|
||||
to: null,
|
||||
participant: null,
|
||||
fromMe: true,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
_data: {
|
||||
Chat: '11111111111@s.whatsapp.net',
|
||||
Sender: '11111111111@s.whatsapp.net',
|
||||
IsFromMe: false,
|
||||
IsGroup: false,
|
||||
AddressingMode: '',
|
||||
SenderAlt: '',
|
||||
RecipientAlt: '',
|
||||
BroadcastListOwner: '',
|
||||
BroadcastRecipients: null,
|
||||
MessageIDs: ['3333333333333333333333'],
|
||||
Type: 'read',
|
||||
MessageSender: '',
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
lid: '144444444444444@lid',
|
||||
jid: '444444444444:42@s.whatsapp.net',
|
||||
pushName: '',
|
||||
},
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'GOWS',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
engine: 'GOWS' as WAHAEngine,
|
||||
},
|
||||
NOWEB: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
||||
from: '11111111111@c.us',
|
||||
fromMe: true,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
lid: '144444444444444@lid',
|
||||
},
|
||||
engine: 'NOWEB',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'NOWEB',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
},
|
||||
WEBJS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_AAA',
|
||||
from: '444444444444@c.us',
|
||||
fromMe: true,
|
||||
source: 'app',
|
||||
to: '11111111111@c.us',
|
||||
body: 'Nn',
|
||||
hasMedia: false,
|
||||
media: null,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
vCards: [],
|
||||
_data: {
|
||||
id: {
|
||||
fromMe: true,
|
||||
remote: '11111111111@c.us',
|
||||
id: 'AAA',
|
||||
_serialized: 'true_11111111111@c.us_AAA',
|
||||
},
|
||||
viewed: false,
|
||||
from: '444444444444@c.us',
|
||||
to: '11111111111@c.us',
|
||||
author: '444444444444@c.us',
|
||||
ack: 3,
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
},
|
||||
engine: 'WEBJS',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'WEBJS',
|
||||
tier: 'PLUS',
|
||||
browser: '/usr/bin/google-chrome-stable',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Participant received My message (DEVICE ack)',
|
||||
expected: false,
|
||||
GOWS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack' as WAHAEvents,
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_3333333333333333333333',
|
||||
from: '11111111111@c.us',
|
||||
to: null,
|
||||
participant: null,
|
||||
fromMe: true,
|
||||
ack: 2,
|
||||
ackName: 'DEVICE',
|
||||
_data: {
|
||||
Chat: '11111111111@s.whatsapp.net',
|
||||
Sender: '11111111111:3@s.whatsapp.net',
|
||||
IsFromMe: false,
|
||||
IsGroup: false,
|
||||
AddressingMode: '',
|
||||
SenderAlt: '',
|
||||
RecipientAlt: '',
|
||||
BroadcastListOwner: '',
|
||||
BroadcastRecipients: null,
|
||||
MessageIDs: ['3333333333333333333333'],
|
||||
Type: '',
|
||||
MessageSender: '',
|
||||
},
|
||||
},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
lid: '144444444444444@lid',
|
||||
jid: '444444444444:42@s.whatsapp.net',
|
||||
pushName: '',
|
||||
},
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'GOWS',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
engine: 'GOWS' as WAHAEngine,
|
||||
},
|
||||
NOWEB: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
||||
from: '11111111111@c.us',
|
||||
fromMe: true,
|
||||
ack: 2,
|
||||
ackName: 'DEVICE',
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
lid: '1144444444444444@lid',
|
||||
},
|
||||
engine: 'NOWEB',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'NOWEB',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
},
|
||||
WEBJS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_11111111111@c.us_AAA',
|
||||
from: '444444444444@c.us',
|
||||
fromMe: true,
|
||||
source: 'app',
|
||||
to: '11111111111@c.us',
|
||||
body: 'Nn',
|
||||
hasMedia: false,
|
||||
media: null,
|
||||
ack: 2,
|
||||
ackName: 'DEVICE',
|
||||
vCards: [],
|
||||
_data: {
|
||||
id: {
|
||||
fromMe: true,
|
||||
remote: '11111111111@c.us',
|
||||
id: 'AAA',
|
||||
_serialized: 'true_11111111111@c.us_AAA',
|
||||
},
|
||||
from: '444444444444@c.us',
|
||||
to: '11111111111@c.us',
|
||||
author: '444444444444@c.us',
|
||||
ack: 2,
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
},
|
||||
engine: 'WEBJS',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'WEBJS',
|
||||
tier: 'PLUS',
|
||||
browser: '/usr/bin/google-chrome-stable',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Me read Participant message on another device (READ ack)',
|
||||
expected: false,
|
||||
GOWS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack' as WAHAEvents,
|
||||
payload: {
|
||||
id: 'false_11111111111@c.us_3333333333333333333333',
|
||||
from: '11111111111@c.us',
|
||||
to: null,
|
||||
participant: null,
|
||||
fromMe: false,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
_data: {
|
||||
Chat: '11111111111@s.whatsapp.net',
|
||||
Sender: '444444444444@s.whatsapp.net',
|
||||
IsFromMe: true,
|
||||
IsGroup: false,
|
||||
AddressingMode: '',
|
||||
SenderAlt: '',
|
||||
RecipientAlt: '',
|
||||
BroadcastListOwner: '',
|
||||
BroadcastRecipients: null,
|
||||
MessageIDs: ['3333333333333333333333'],
|
||||
Type: 'read',
|
||||
MessageSender: '11111111111@s.whatsapp.net',
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
lid: '144444444444444@lid',
|
||||
jid: '444444444444:42@s.whatsapp.net',
|
||||
pushName: '',
|
||||
},
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'GOWS',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
engine: 'GOWS' as WAHAEngine,
|
||||
},
|
||||
NOWEB: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: '11111111111@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
||||
from: '11111111111@c.us',
|
||||
fromMe: false,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
lid: '1144444444444444@lid',
|
||||
},
|
||||
engine: 'NOWEB',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'NOWEB',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
},
|
||||
WEBJS: null,
|
||||
},
|
||||
{
|
||||
name: 'Participant read My Group Message (READ ack)',
|
||||
expected: false,
|
||||
GOWS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
payload: {
|
||||
id: 'true_222222222222222222@g.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_444444444444@c.us',
|
||||
from: '222222222222222222@g.us',
|
||||
to: '011111111111111@lid',
|
||||
participant: '011111111111111@lid',
|
||||
fromMe: true,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
_data: {
|
||||
Chat: '222222222222222222@g.us',
|
||||
Sender: '011111111111111@lid',
|
||||
IsFromMe: false,
|
||||
IsGroup: true,
|
||||
AddressingMode: '',
|
||||
SenderAlt: '',
|
||||
RecipientAlt: '',
|
||||
BroadcastListOwner: '',
|
||||
BroadcastRecipients: null,
|
||||
MessageIDs: ['AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'],
|
||||
Type: 'read',
|
||||
MessageSender: '',
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
lid: '144444444444444@lid',
|
||||
jid: '444444444444:42@s.whatsapp.net',
|
||||
pushName: '',
|
||||
},
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'GOWS',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
},
|
||||
NOWEB: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_222222222222222222@g.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_444444444444@c.us',
|
||||
from: '222222222222222222@g.us',
|
||||
to: '222222222222222222@g.us',
|
||||
participant: '011111111111111@lid',
|
||||
fromMe: true,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
_data: {
|
||||
key: {
|
||||
remoteJid: '222222222222222222@g.us',
|
||||
id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
||||
fromMe: true,
|
||||
participant: '011111111111111@lid',
|
||||
},
|
||||
receipt: {
|
||||
userJid: '011111111111111@lid',
|
||||
},
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
lid: '1144444444444444@lid',
|
||||
},
|
||||
engine: 'NOWEB',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'NOWEB',
|
||||
tier: 'PLUS',
|
||||
browser: null,
|
||||
},
|
||||
},
|
||||
WEBJS: {
|
||||
id: 'evt_00000000000000000000000000',
|
||||
session: 'default',
|
||||
event: 'message.ack',
|
||||
payload: {
|
||||
id: 'true_222222222222222222@g.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_444444444444@c.us',
|
||||
from: '222222222222222222@g.us',
|
||||
to: '222222222222222222@g.us',
|
||||
participant: '011111111111111@lid',
|
||||
fromMe: false,
|
||||
ack: 3,
|
||||
ackName: 'READ',
|
||||
_data: {
|
||||
tag: 'receipt',
|
||||
attrs: {
|
||||
from: {
|
||||
$1: {
|
||||
type: 0,
|
||||
user: '222222222222222222',
|
||||
server: 'g.us',
|
||||
},
|
||||
},
|
||||
type: 'read',
|
||||
id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
||||
participant: {
|
||||
$1: {
|
||||
type: 1,
|
||||
user: '011111111111111',
|
||||
device: 0,
|
||||
domainType: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
content: null,
|
||||
},
|
||||
},
|
||||
metadata: {},
|
||||
me: {
|
||||
id: '444444444444@c.us',
|
||||
pushName: '',
|
||||
},
|
||||
engine: 'WEBJS',
|
||||
environment: {
|
||||
version: '2025.10.4',
|
||||
engine: 'WEBJS',
|
||||
tier: 'PLUS',
|
||||
browser: '/usr/bin/google-chrome-stable',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('ShouldMarkAsReadInChatWoot', () => {
|
||||
const engines = ['GOWS', 'NOWEB', 'WEBJS'];
|
||||
for (const engine of engines) {
|
||||
describe(engine, () => {
|
||||
for (const param of ShouldMarkAsReadCases) {
|
||||
const name = `[${param.expected}] ${param.name}`;
|
||||
const event = param[engine];
|
||||
const testfn = event ? test : test.skip;
|
||||
const expected = param.expected;
|
||||
testfn(name, () => {
|
||||
// Test
|
||||
const result = ShouldMarkAsReadInChatWoot(event);
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { WAHAWebhookMessageAck } from '@waha/structures/webhooks.dto';
|
||||
import { isJidCusFormat } from '@waha/utils/wa';
|
||||
import { WAMessageAck } from '@waha/structures/enums.dto';
|
||||
import { isLidUser, toCusFormat } from '@waha/core/utils/jids';
|
||||
|
||||
export function ShouldMarkAsReadInChatWoot(
|
||||
event: WAHAWebhookMessageAck,
|
||||
): boolean {
|
||||
// Mark as seen only if it's DM
|
||||
// Ignore groups and other multiple participants chats
|
||||
const chatId = event.payload.from;
|
||||
if (!isJidCusFormat(chatId) && !isLidUser(chatId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const payload = event.payload;
|
||||
// Only READ and PLAYED
|
||||
const read = payload.ack === WAMessageAck.READ;
|
||||
const played = payload.ack == WAMessageAck.PLAYED;
|
||||
if (!read && !played) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only process when OUR message (fromMe: true) was read by recipient
|
||||
if (!payload.fromMe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark ChatWoot conversation as read when recipient reads our message
|
||||
return true;
|
||||
}
|
||||
@@ -11,7 +11,8 @@ import { WhatsappToMarkdown } from '@waha/apps/chatwoot/messages/to/chatwoot/uti
|
||||
import { WAMessage } from '@waha/structures/responses.dto';
|
||||
import type { proto } from '@adiwajshing/baileys';
|
||||
import * as lodash from 'lodash';
|
||||
import { fetchBuffer } from '@waha/core/abc/session.abc';
|
||||
|
||||
import { fetchBuffer } from '@waha/utils/fetch';
|
||||
|
||||
export class FacebookAdMessage implements MessageToChatWootConverter {
|
||||
constructor(
|
||||
|
||||
@@ -116,8 +116,7 @@ describe('PixMessage - pt-BR', () => {
|
||||
****Tipo:**** PHONE
|
||||
****Referência:**** 4TB11111111
|
||||
|
||||
💳 ****PIX Copia e Cola enviado****
|
||||
`;
|
||||
💳 ****PIX Copia e Cola enviado****`;
|
||||
|
||||
expect(protoMessage).not.toBeNull();
|
||||
expect(result).not.toBeNull();
|
||||
@@ -237,8 +236,7 @@ describe('PixMessage - pt-BR', () => {
|
||||
****Valor:**** R$\u00A025,12
|
||||
****Referência:**** 4TB11111111
|
||||
|
||||
💳 ****PIX Copia e Cola enviado****
|
||||
`;
|
||||
💳 ****PIX Copia e Cola enviado****`;
|
||||
|
||||
expect(protoMessage).not.toBeNull();
|
||||
expect(result).not.toBeNull();
|
||||
|
||||
@@ -14,4 +14,43 @@ describe('WhatsappToMarkdown', () => {
|
||||
const expected = `**bold** | *italic* | ~~strike~~ | \`one line code\` | \`\`\`\nmultiple lines\`\`\` `;
|
||||
expect(WhatsappToMarkdown(input)).toBe(expected);
|
||||
});
|
||||
|
||||
// Tests for URL protection
|
||||
it('preserves URLs with single underscore', () => {
|
||||
const input = 'https://example.com/page_name';
|
||||
expect(WhatsappToMarkdown(input)).toBe('https://example.com/page_name');
|
||||
});
|
||||
|
||||
it('preserves URLs with double underscores', () => {
|
||||
const input = 'https://en.wikipedia.org/wiki/Sarah_Jessica_Parker';
|
||||
expect(WhatsappToMarkdown(input)).toBe(
|
||||
'https://en.wikipedia.org/wiki/Sarah_Jessica_Parker',
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves URLs with multiple underscores', () => {
|
||||
const input = 'https://example.com/a_b_c_test';
|
||||
expect(WhatsappToMarkdown(input)).toBe('https://example.com/a_b_c_test');
|
||||
});
|
||||
|
||||
it('handles mixed text with URLs and formatting', () => {
|
||||
const input = 'Veja *isso* em https://example.com/test_link e _aquilo_';
|
||||
const expected =
|
||||
'Veja **isso** em https://example.com/test_link e *aquilo*';
|
||||
expect(WhatsappToMarkdown(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it('handles multiple URLs in same text', () => {
|
||||
const input =
|
||||
'Links: https://example.com/page_1 e https://example.com/page_2';
|
||||
expect(WhatsappToMarkdown(input)).toBe(
|
||||
'Links: https://example.com/page_1 e https://example.com/page_2',
|
||||
);
|
||||
});
|
||||
|
||||
it('handles URLs with underscores and regular italic formatting', () => {
|
||||
const input = 'URL: https://example.com/test_page e texto _em itálico_';
|
||||
const expected = 'URL: https://example.com/test_page e texto *em itálico*';
|
||||
expect(WhatsappToMarkdown(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
import { UrlProtection } from '@waha/apps/chatwoot/messages/to/markdown';
|
||||
|
||||
export function WhatsappToMarkdown(text: string): string {
|
||||
if (!text) {
|
||||
return text;
|
||||
@@ -5,13 +7,22 @@ export function WhatsappToMarkdown(text: string): string {
|
||||
if (text == '') {
|
||||
return '';
|
||||
}
|
||||
return (
|
||||
text
|
||||
// Bold: *bold* → **bold**
|
||||
.replace(/\*(.*?)\*/g, '**$1**')
|
||||
// Strikethrough: ~strike~ → ~~strike~~
|
||||
.replace(/~(.*?)~/g, '~~$1~~')
|
||||
// Italic: _italic_ → *italic*
|
||||
.replace(/_(.*?)_/g, '*$1*')
|
||||
);
|
||||
|
||||
// Extract and protect URLs before formatting transformations
|
||||
const protection = new UrlProtection();
|
||||
const urls = protection.protect(text);
|
||||
text = urls.text;
|
||||
|
||||
// Apply markdown transformations to "clean" text
|
||||
let result = text
|
||||
// Bold: *bold* → **bold**
|
||||
.replace(/\*(.*?)\*/g, '**$1**')
|
||||
// Strikethrough: ~strike~ → ~~strike~~
|
||||
.replace(/~(.*?)~/g, '~~$1~~')
|
||||
// Italic: _italic_ → *italic*
|
||||
.replace(/_(.*?)_/g, '*$1*');
|
||||
|
||||
// Restore original URLs after all transformations
|
||||
result = urls.restore(result);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
const DEFAULT_PLACEHOLDER_PREFIX = 'URLPLACEHOLDER';
|
||||
const URL_REGEX = /https?:\/\/[^\s]+/g;
|
||||
|
||||
export class UrlProtection {
|
||||
/** Replaces URLs with placeholders so downstream formatters don't touch them. */
|
||||
constructor(
|
||||
private readonly placeholder: string = DEFAULT_PLACEHOLDER_PREFIX,
|
||||
) {}
|
||||
|
||||
protect(text: string): ProtectedUrlText {
|
||||
const urls: string[] = [];
|
||||
const result = text.replace(URL_REGEX, (url) => {
|
||||
const index = urls.length;
|
||||
urls.push(url);
|
||||
return `${this.placeholder}${index}`;
|
||||
});
|
||||
|
||||
return new ProtectedUrlText(result, urls, this.placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
export class ProtectedUrlText {
|
||||
/** Carries protected text and restores URLs back into place. */
|
||||
constructor(
|
||||
public text: string,
|
||||
private readonly urls: string[],
|
||||
private readonly placeholder: string,
|
||||
) {}
|
||||
|
||||
restore(text: string = this.text): string {
|
||||
return this.urls.reduce((acc, url, index) => {
|
||||
const placeholder = `${this.placeholder}${index}`;
|
||||
return acc.replace(placeholder, url);
|
||||
}, text);
|
||||
}
|
||||
}
|
||||
@@ -14,4 +14,41 @@ describe('MarkdownToWhatsApp', () => {
|
||||
const expected = `Here is a code block:\n\`\`\`some code\`\`\`\n*bold* _italic_ ~strike~ example (http://example.com)\n* item`;
|
||||
expect(MarkdownToWhatsApp(input)).toBe(expected);
|
||||
});
|
||||
|
||||
// Tests for URL protection
|
||||
it('preserves URLs with multiple underscores', () => {
|
||||
const input = 'https://example.com/page__name__test';
|
||||
expect(MarkdownToWhatsApp(input)).toBe(
|
||||
'https://example.com/page__name__test',
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves URLs with double underscores', () => {
|
||||
const input = 'https://en.wikipedia.org/wiki/Sarah_Jessica_Parker';
|
||||
expect(MarkdownToWhatsApp(input)).toBe(
|
||||
'https://en.wikipedia.org/wiki/Sarah_Jessica_Parker',
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves URLs inside markdown links', () => {
|
||||
const input =
|
||||
'Veja [perfil](https://en.wikipedia.org/wiki/Sarah_Jessica_Parker)';
|
||||
const expected =
|
||||
'Veja perfil (https://en.wikipedia.org/wiki/Sarah_Jessica_Parker)';
|
||||
expect(MarkdownToWhatsApp(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it('handles mixed text with URLs and formatting', () => {
|
||||
const input = 'Veja **isso** em https://example.com/test_link e _aquilo_';
|
||||
const expected = 'Veja *isso* em https://example.com/test_link e _aquilo_';
|
||||
expect(MarkdownToWhatsApp(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it('handles multiple URLs in the same text', () => {
|
||||
const input =
|
||||
'Links: https://example.com/page_1 e https://example.com/page_2';
|
||||
expect(MarkdownToWhatsApp(input)).toBe(
|
||||
'Links: https://example.com/page_1 e https://example.com/page_2',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
import { MessagesForRead } from '@waha/core/utils/convertors';
|
||||
import {
|
||||
IgnoreJidConfig,
|
||||
isJidNewsletter,
|
||||
isJidBroadcast,
|
||||
isJidNewsletter,
|
||||
JidFilter,
|
||||
} from '@waha/core/utils/jids';
|
||||
import {
|
||||
@@ -43,7 +43,6 @@ import { complete } from '@waha/utils/reactive/complete';
|
||||
import { SwitchObservable } from '@waha/utils/reactive/SwitchObservable';
|
||||
import axios from 'axios';
|
||||
import axiosRetry from 'axios-retry';
|
||||
import { Agent as HttpsAgent } from 'https';
|
||||
import * as fs from 'fs';
|
||||
import * as lodash from 'lodash';
|
||||
import * as NodeCache from 'node-cache';
|
||||
@@ -129,6 +128,7 @@ import {
|
||||
import { IMediaManager } from '../media/IMediaManager';
|
||||
import { QR } from '../QR';
|
||||
import { DataStore } from './DataStore';
|
||||
import { fetchBuffer } from '@waha/utils/fetch';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const qrcode = require('qrcode-terminal');
|
||||
@@ -1081,21 +1081,6 @@ export abstract class WhatsappSession {
|
||||
}
|
||||
}
|
||||
|
||||
const InsecureHttpsAgent = new HttpsAgent({
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
|
||||
export async function fetchBuffer(url: string): Promise<Buffer> {
|
||||
return axios
|
||||
.get(url, {
|
||||
responseType: 'arraybuffer',
|
||||
httpsAgent: InsecureHttpsAgent,
|
||||
})
|
||||
.then((res) => {
|
||||
return Buffer.from(res.data);
|
||||
});
|
||||
}
|
||||
|
||||
export function getGroupInviteLink(code: string) {
|
||||
if (code.startsWith('https://')) {
|
||||
return code;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { proto, WAMessageKey } from '@adiwajshing/baileys';
|
||||
import { normalizeMessageContent, WAMessageKey } from '@adiwajshing/baileys';
|
||||
import { proto } from '@adiwajshing/baileys';
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
import { connectivityState } from '@grpc/grpc-js';
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
@@ -166,6 +167,7 @@ import {
|
||||
isLabelUpsertEvent,
|
||||
} from './labels.gows';
|
||||
import esm from '@waha/vendor/esm';
|
||||
import { IsEditedMessage } from '@waha/core/utils/pwa';
|
||||
|
||||
enum WhatsMeowEvent {
|
||||
CONNECTED = 'gows.ConnectedEventData',
|
||||
@@ -491,19 +493,15 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
|
||||
// Handle edited messages
|
||||
const messagesEdited$ = messages$.pipe(
|
||||
filter((msg) => {
|
||||
return (
|
||||
msg?.Message?.protocolMessage?.type === 14 &&
|
||||
msg?.Message?.protocolMessage?.editedMessage !== undefined
|
||||
);
|
||||
}),
|
||||
filter((message) => IsEditedMessage(message.Message)),
|
||||
mergeMap(async (message): Promise<WAMessageEditedBody> => {
|
||||
const waMessage = await this.toWAMessage(message);
|
||||
const content = normalizeMessageContent(message.Message);
|
||||
// Extract the body from editedMessage using extractBody function
|
||||
const body =
|
||||
extractBody(message.Message.protocolMessage.editedMessage) || '';
|
||||
const body = extractBody(content.protocolMessage.editedMessage) || '';
|
||||
// Extract the original message ID from protocolMessage.key
|
||||
const editedMessageId = message.Message.protocolMessage.key?.ID;
|
||||
// @ts-ignore
|
||||
const editedMessageId = content.protocolMessage.key?.ID;
|
||||
return {
|
||||
...waMessage,
|
||||
body: body,
|
||||
@@ -1948,17 +1946,18 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
// if there is no text or media message
|
||||
if (!message) return;
|
||||
if (!message.Message) return;
|
||||
// Ignore reactions, we have a dedicated handler for that
|
||||
if (message.Message.reactionMessage) return;
|
||||
// Ignore poll votes, we have a dedicated handler for that
|
||||
if (message.Message.pollUpdateMessage) return;
|
||||
// Ignore event response, we have a dedicated handler for that
|
||||
if (message.Message.encEventResponseMessage) return;
|
||||
// Ignore protocol messages
|
||||
if (message.Message.protocolMessage) return;
|
||||
|
||||
const normalizedContent = esm.b.normalizeMessageContent(message.Message);
|
||||
const contentType = esm.b.getContentType(normalizedContent);
|
||||
const content = esm.b.normalizeMessageContent(message.Message);
|
||||
// Ignore reactions, we have a dedicated handler for that
|
||||
if (content.reactionMessage) return;
|
||||
// Ignore poll votes, we have a dedicated handler for that
|
||||
if (content.pollUpdateMessage) return;
|
||||
// Ignore event response, we have a dedicated handler for that
|
||||
if (content.encEventResponseMessage) return;
|
||||
// Ignore protocol messages
|
||||
if (content.protocolMessage) return;
|
||||
|
||||
const contentType = esm.b.getContentType(content);
|
||||
// Ignore device sent message
|
||||
if (contentType == 'deviceSentMessage') {
|
||||
return;
|
||||
|
||||
@@ -199,6 +199,7 @@ import { NowebPersistentStore } from './store/NowebPersistentStore';
|
||||
import { NowebStorageFactoryCore } from './store/NowebStorageFactoryCore';
|
||||
import { ensureNumber, extractMediaContent } from './utils';
|
||||
import { Agents } from '@waha/core/engines/noweb/types';
|
||||
import { IsEditedMessage } from '@waha/core/utils/pwa';
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const promiseRetry = require('promise-retry');
|
||||
|
||||
@@ -608,14 +609,9 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
// https://github.com/WhiskeySockets/Baileys/pull/855/
|
||||
this.sock.ev.on('messages.upsert', ({ messages }) => {
|
||||
for (const message of messages) {
|
||||
const content = normalizeMessageContent(message.message);
|
||||
const protocolMsg = content?.protocolMessage;
|
||||
if (
|
||||
protocolMsg !== null &&
|
||||
protocolMsg !== undefined &&
|
||||
protocolMsg.editedMessage &&
|
||||
protocolMsg.key
|
||||
) {
|
||||
if (IsEditedMessage(message.message)) {
|
||||
const content = normalizeMessageContent(message.message);
|
||||
const protocolMsg = content?.protocolMessage;
|
||||
this.sock?.ev.emit('messages.update', [
|
||||
{
|
||||
key: {
|
||||
@@ -1897,22 +1893,15 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
this.events2.get(WAHAEvents.MESSAGE_REVOKED).switch(messagesRevoked$);
|
||||
|
||||
// Handle edited messages
|
||||
// @ts-ignore
|
||||
const messagesEdited$ = messagesUpsert$.pipe(
|
||||
filter(
|
||||
(message) =>
|
||||
// @ts-ignore
|
||||
message.message?.protocolMessage?.type ===
|
||||
proto.Message.ProtocolMessage.Type.MESSAGE_EDIT &&
|
||||
message.message?.protocolMessage?.editedMessage !== undefined,
|
||||
),
|
||||
filter((message) => IsEditedMessage(message.message)),
|
||||
mergeMap(async (message): Promise<WAMessageEditedBody> => {
|
||||
const waMessage = this.toWAMessage(message);
|
||||
// Extract the body from editedMessage using extractBody function
|
||||
const body =
|
||||
extractBody(message.message.protocolMessage.editedMessage) || '';
|
||||
const content = normalizeMessageContent(message.message);
|
||||
const body = extractBody(content.protocolMessage.editedMessage) || '';
|
||||
// Extract the original message ID from protocolMessage.key
|
||||
const editedMessageId = message.message.protocolMessage.key?.id;
|
||||
const editedMessageId = content.protocolMessage.key?.id;
|
||||
return {
|
||||
...waMessage,
|
||||
body: body,
|
||||
@@ -2208,11 +2197,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
)
|
||||
return;
|
||||
// Ignore edit, we have a dedicated event for that
|
||||
if (
|
||||
message.message?.protocolMessage?.type ===
|
||||
proto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
||||
)
|
||||
return;
|
||||
if (IsEditedMessage(message.message)) return;
|
||||
if (
|
||||
message.message?.protocolMessage?.type ===
|
||||
proto.Message.ProtocolMessage.Type.EPHEMERAL_SYNC_RESPONSE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { jidNormalizedUser, WAMessageKey } from '@adiwajshing/baileys';
|
||||
import type { WAMessageKey } from '@adiwajshing/baileys';
|
||||
import { ensureSuffix } from '@waha/core/abc/session.abc';
|
||||
|
||||
export function isJidNewsletter(jid: string) {
|
||||
@@ -36,6 +36,10 @@ export function isPnUser(jid: string) {
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeJid(jid: string): string {
|
||||
return jid.replace(/:\d+(?=@)/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from 11111111111@c.us to 11111111111@s.whatsapp.net
|
||||
* @param chatId
|
||||
@@ -135,7 +139,7 @@ export function toCusFormat(remoteJid) {
|
||||
return remoteJid;
|
||||
}
|
||||
if (isLidUser(remoteJid)) {
|
||||
return jidNormalizedUser(remoteJid);
|
||||
return normalizeJid(remoteJid);
|
||||
}
|
||||
if (isJidNewsletter(remoteJid)) {
|
||||
return remoteJid;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Proto WhatsApp Utils
|
||||
*/
|
||||
|
||||
import { normalizeMessageContent, proto } from '@adiwajshing/baileys';
|
||||
|
||||
export function IsEditedMessage(message: proto.IMessage): boolean {
|
||||
message = normalizeMessageContent(message);
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
message?.protocolMessage?.type !==
|
||||
proto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (message?.protocolMessage?.editedMessage == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -150,7 +150,7 @@ export class SessionConfig {
|
||||
})
|
||||
@IsDynamicObject()
|
||||
@IsOptional()
|
||||
metadata?: Map<string, string>;
|
||||
metadata?: Record<string, string>;
|
||||
|
||||
@ApiProperty({
|
||||
example: null,
|
||||
@@ -225,6 +225,12 @@ export class MeInfo {
|
||||
})
|
||||
lid?: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: '123123:123@s.whatsapp.net',
|
||||
description: 'Your id with device number',
|
||||
})
|
||||
jid?: string;
|
||||
|
||||
pushName: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ export class WAHAWebhook<Payload = any> {
|
||||
},
|
||||
description: 'Metadata for the session.',
|
||||
})
|
||||
metadata?: Map<string, string>;
|
||||
metadata?: Record<string, string>;
|
||||
|
||||
@ApiProperty({
|
||||
example: WAHAEngine.WEBJS,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import axios from 'axios';
|
||||
import { Agent as HttpsAgent } from 'https';
|
||||
|
||||
const InsecureHttpsAgent = new HttpsAgent({
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
|
||||
export async function fetchBuffer(url: string): Promise<Buffer> {
|
||||
return axios
|
||||
.get(url, {
|
||||
responseType: 'arraybuffer',
|
||||
httpsAgent: InsecureHttpsAgent,
|
||||
})
|
||||
.then((res) => {
|
||||
return Buffer.from(res.data);
|
||||
});
|
||||
}
|
||||
+1
-1
@@ -30,7 +30,7 @@ export function getWAHAVersion(): WAHAVersion {
|
||||
}
|
||||
|
||||
export const VERSION: WAHAEnvironment = {
|
||||
version: '2025.10.3',
|
||||
version: '2025.10.4',
|
||||
engine: getEngineName(),
|
||||
tier: getWAHAVersion(),
|
||||
browser:
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"dashboard": {
|
||||
"repo": "devlikeapro/dashboard",
|
||||
"ref": "583ee12cd77a95ca48c25dece822e3e9b4e01a23"
|
||||
"ref": "8345fb8594a9f8f51fc0a593d5cc1a2e4e786960"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ __metadata:
|
||||
version: 6
|
||||
cacheKey: 8
|
||||
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-10-10":
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-10-19":
|
||||
version: 7.0.0-rc.5
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=dc9b6b7589ba1d71ec85cff4a789b5709a60a714"
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=df07435e41a5b6062c51a4a74393558cecf8fc50"
|
||||
dependencies:
|
||||
"@cacheable/node-cache": ^1.4.0
|
||||
"@hapi/boom": ^9.1.3
|
||||
@@ -31,7 +31,7 @@ __metadata:
|
||||
optional: true
|
||||
link-preview-js:
|
||||
optional: true
|
||||
checksum: d79aca449353f170374e6647efe09a2e871219e0af176d62796f68860ad619ce715736380250521e304d3ca28c5af4baa397ee0a8875468f8c7ad026e95028b6
|
||||
checksum: 065a0a3e086e307ef805321355914c97282d279e7cbe2350118562373c0d36aaf877b0789d7e339f45f9c24e31a425f699b2f905411500522d0dc95a31c8986a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -12511,7 +12511,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "waha@workspace:."
|
||||
dependencies:
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-10-10"
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-10-19"
|
||||
"@adiwajshing/keyed-db": ^0.2.4
|
||||
"@aws-sdk/client-s3": ^3.633.0
|
||||
"@aws-sdk/s3-request-presigner": ^3.633.0
|
||||
|
||||
Reference in new issue
Block a user