feat(WEBJS, NOWEB): message capping API and events mention #2186
This commit is contained in:
1 parent
f26d43b299
commit
5ddbeb995e
7 files changed
+75
-15
No files matched your search
@@ -106,8 +106,7 @@ class SessionsController {
|
||||
description:
|
||||
'Fetch a fresh new-chat message capping (quota) state from WhatsApp. ' +
|
||||
'The same value is also available under me.messageCapping in the session ' +
|
||||
'info, and changes are pushed through the session.status event. ' +
|
||||
'GOWS engine only.',
|
||||
'info, and changes are pushed through the session.status event.',
|
||||
})
|
||||
@CheckPolicies(CanSession(Action.Read, FromParam('session')))
|
||||
fetchMessageCapping(
|
||||
|
||||
@@ -175,8 +175,7 @@ export class SessionTools extends McpController {
|
||||
@Tool('sessions-capping', {
|
||||
title: 'Get message capping',
|
||||
description:
|
||||
'Fetch the account new-chat message capping (per-cycle quota). ' +
|
||||
'GOWS engine only.',
|
||||
'Fetch the account new-chat message capping (per-cycle quota).',
|
||||
inputSchema: SessionNameInput,
|
||||
annotations: {
|
||||
readOnlyHint: true,
|
||||
|
||||
@@ -13,17 +13,18 @@ function parseCappingTimestamp(value: any): number | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize gows' MessageCapping payload (xwa2_message_capping_info).
|
||||
* Normalize the message capping payload (xwa2_message_capping_info) - the shape is the same
|
||||
* across engines: GOWS gRPC event, NOWEB Baileys fetch/push, WEBJS injected fetch/local read.
|
||||
*/
|
||||
export function parseGowsMessageCapping(data: any): MessageCappingData {
|
||||
export function parseMessageCapping(data: any): MessageCappingData {
|
||||
const cappingStatus = (data?.capping_status ??
|
||||
MessageCappingStatus.NONE) as MessageCappingStatus;
|
||||
return {
|
||||
cappingStatus: cappingStatus,
|
||||
// total/used quota are Go ints, so numbers here; -1 total means "no cap"
|
||||
// -1 total means "no cap"
|
||||
totalQuota: typeof data?.total_quota === 'number' ? data.total_quota : -1,
|
||||
usedQuota: typeof data?.used_quota === 'number' ? data.used_quota : 0,
|
||||
// cycle timestamps are unix seconds strings, absent when zero (Go's omitzero)
|
||||
// cycle timestamps are unix seconds strings (or ms numbers from WEBJS local reads)
|
||||
cycleStart: parseCappingTimestamp(data?.cycle_start_timestamp),
|
||||
cycleEnd: parseCappingTimestamp(data?.cycle_end_timestamp),
|
||||
mvStatus: data?.mv_status ?? null,
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
parseJsonList,
|
||||
statusToAck,
|
||||
} from '@waha/core/engines/gows/helpers';
|
||||
import { parseGowsMessageCapping } from '@waha/core/engines/gows/capping';
|
||||
import { parseMessageCapping } from '@waha/core/abc/capping';
|
||||
import { parseGowsReachoutTimelock } from '@waha/core/engines/gows/reachouttimelock';
|
||||
import { GowsAuthFactoryCore } from '@waha/core/engines/gows/store/GowsAuthFactoryCore';
|
||||
import {
|
||||
@@ -483,7 +483,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
this.reachoutTimelock.update(parseGowsReachoutTimelock(data));
|
||||
});
|
||||
events.on(WhatsMeowEvent.MESSAGE_CAPPING, (data) => {
|
||||
this.messageCapping.update(parseGowsMessageCapping(data));
|
||||
this.messageCapping.update(parseMessageCapping(data));
|
||||
});
|
||||
events.on(WhatsMeowEvent.PRESENCE, (event: gows.Presence) => {
|
||||
if (isJidGroup(event.From)) {
|
||||
@@ -2290,7 +2290,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
const response = await promisify(this.client.FetchMessageCapping)(
|
||||
this.session,
|
||||
);
|
||||
const capping = parseGowsMessageCapping(parseJson(response));
|
||||
const capping = parseMessageCapping(parseJson(response));
|
||||
// Keep the tracker in sync so MeInfo and 'session.status' reflect the fetch
|
||||
this.messageCapping.update(capping);
|
||||
return capping;
|
||||
|
||||
@@ -44,6 +44,7 @@ import type {
|
||||
import { ILogger } from '@adiwajshing/baileys/lib/Utils/logger';
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
import { parseMessageCapping } from '@waha/core/abc/capping';
|
||||
import {
|
||||
getChannelInviteLink,
|
||||
getPublicUrlFromDirectPath,
|
||||
@@ -175,6 +176,7 @@ import {
|
||||
import { WAMessage, WAMessageReaction } from '@waha/structures/responses.dto';
|
||||
import {
|
||||
MeInfo,
|
||||
MessageCappingData,
|
||||
ReachoutTimelockEnforcementType,
|
||||
} from '@waha/structures/sessions.dto';
|
||||
import { EnsureSeconds } from '@waha/utils/timehelper';
|
||||
@@ -562,6 +564,9 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
|
||||
protected listenConnectionEvents() {
|
||||
this.logger.debug(`Start listening ${BaileysEvents.CONNECTION_UPDATE}...`);
|
||||
this.sock.ev.on('message-capping.update', (data) => {
|
||||
this.messageCapping.update(parseMessageCapping(data));
|
||||
});
|
||||
this.sock.ev.on('connection.update', async (update) => {
|
||||
const { connection, lastDisconnect, qr, isNewLogin } = update;
|
||||
if (update.reachoutTimeLock) {
|
||||
@@ -590,6 +595,15 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
this.sock?.fetchAccountReachoutTimelock?.().catch((error) => {
|
||||
this.logger.warn(`Failed to fetch reachout timelock: ${error}`);
|
||||
});
|
||||
// Same for the new-chat message capping - there is no push on (re)connect, only on changes
|
||||
this.sock
|
||||
?.fetchNewChatMessageCap?.()
|
||||
.then((data) => {
|
||||
this.messageCapping.update(parseMessageCapping(data));
|
||||
})
|
||||
.catch((error) => {
|
||||
this.logger.warn(`Failed to fetch message capping: ${error}`);
|
||||
});
|
||||
// Do we need to resubscribe?
|
||||
// Ideally not, we need to explicitly call interesting
|
||||
// jids every 1 minute
|
||||
@@ -893,6 +907,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
pushName: me.name,
|
||||
lid: jidNormalizedUser(me.lid),
|
||||
reachoutTimelock: this.reachoutTimelock.value,
|
||||
messageCapping: this.messageCapping.value,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -983,6 +998,15 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Activity()
|
||||
public async fetchMessageCapping(): Promise<MessageCappingData> {
|
||||
const data = await this.sock.fetchNewChatMessageCap();
|
||||
const capping = parseMessageCapping(data);
|
||||
// Keep the tracker in sync so MeInfo and 'session.status' reflect the fetch
|
||||
this.messageCapping.update(capping);
|
||||
return capping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Other methods
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
import { parseMessageCapping } from '@waha/core/abc/capping';
|
||||
import {
|
||||
getChannelInviteLink,
|
||||
getPublicUrlFromDirectPath,
|
||||
@@ -128,6 +129,7 @@ import {
|
||||
import { BrowserTraceQuery } from '@waha/structures/server.debug.dto';
|
||||
import {
|
||||
MeInfo,
|
||||
MessageCappingData,
|
||||
ReachoutTimelockEnforcementType,
|
||||
} from '@waha/structures/sessions.dto';
|
||||
import { EnsureSeconds } from '@waha/utils/timehelper';
|
||||
@@ -541,6 +543,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
lid: GetSerialized(clientInfo.lid),
|
||||
pushName: clientInfo?.pushname,
|
||||
reachoutTimelock: this.reachoutTimelock.value,
|
||||
messageCapping: this.messageCapping.value,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -579,6 +582,26 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
});
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.MESSAGE_CAPPING_UPDATE, (record: any) => {
|
||||
// Unlike the timelock, a null record means "no local data yet", not "capping lifted"
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
this.messageCapping.update(parseMessageCapping(record));
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.READY, async () => {
|
||||
// Ask WhatsApp for the current message capping state, the same fetch the app runs on startup
|
||||
try {
|
||||
const data = await this.whatsapp.fetchMessageCapping();
|
||||
if (data) {
|
||||
this.messageCapping.update(parseMessageCapping(data));
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.warn(err, 'Failed to fetch message capping');
|
||||
}
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.QR_RECEIVED, async (qr) => {
|
||||
this.logger.debug('QR received');
|
||||
// Convert to image and save
|
||||
@@ -812,6 +835,20 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
return await this.whatsapp.deleteProfilePicture();
|
||||
}
|
||||
|
||||
@Activity()
|
||||
public async fetchMessageCapping(): Promise<MessageCappingData> {
|
||||
const data = await this.whatsapp.fetchMessageCapping();
|
||||
if (!data) {
|
||||
throw new NotImplementedByEngineError(
|
||||
'Message capping is not available in the current WhatsApp Web version',
|
||||
);
|
||||
}
|
||||
const capping = parseMessageCapping(data);
|
||||
// Keep the tracker in sync so MeInfo and 'session.status' reflect the fetch
|
||||
this.messageCapping.update(capping);
|
||||
return capping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups methods
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ __metadata:
|
||||
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2026-04-28":
|
||||
version: 7.0.0-rc14
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=0124c8f073719727fb8db2b08d4b14b81573d82c"
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=080deabc5f48c53cf23700ec1177a8dfabc8e517"
|
||||
dependencies:
|
||||
"@cacheable/node-cache": "npm:^1.4.0"
|
||||
"@hapi/boom": "npm:^9.1.3"
|
||||
@@ -32,7 +32,7 @@ __metadata:
|
||||
optional: true
|
||||
link-preview-js:
|
||||
optional: true
|
||||
checksum: 10/35b77766d9a8eccc8366efa5a0f702b45039df3578b9ac6bc53743305255b9c7f28ca04248c50f30ed7af3d5adcd4842fdeeb557967f21d7dc096c303de8cf55
|
||||
checksum: 10/4d29a66c772b1162ac32e2cfbb33fb9a4afe448ae64948948e38cb0da0d67b1e40b3be9efc51978aefad1186829b10fc41bcb8b91eec5735b7f99ad19c640fb2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14148,7 +14148,7 @@ __metadata:
|
||||
|
||||
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2026-06-26":
|
||||
version: 1.34.7
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=ba9192e34bc57024018a88982efbad416a9279ed"
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=e8aea2332993c6dcacff650eea736dda75001e81"
|
||||
dependencies:
|
||||
archiver: "npm:7.0.1"
|
||||
fluent-ffmpeg: "npm:2.1.3"
|
||||
@@ -14165,7 +14165,7 @@ __metadata:
|
||||
optional: true
|
||||
unzipper:
|
||||
optional: true
|
||||
checksum: 10/915bc0aaddc88e940f670ed026e1f9d419945c42107b6cce3ad4d3a78afe77c535c49927b1619ffe921cd906e3fe55a70d68d76bd62c9d3fe4d90b512548c83d
|
||||
checksum: 10/8c6652657873f45ca3ff89bd2870180dc2c55f930bd98eeec86dbc915b005d1d1a3441df911d6f1f88c268b66f494e6ad903fe1d53061dd6f1ab076ac91c6224
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in new issue
Block a user