From 57d5c212e7ad7baa7108134aa0a44dee77da4480 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa AKSAM Date: Sun, 21 Dec 2025 01:00:50 +0300 Subject: [PATCH 1/2] feat(core): expose archived, pinned, and unreadCount in ChatSummary - Add `archived`, `pinned`, and `unreadCount` fields to `ChatSummary` DTO. - Update `webjs` engine to populate these fields. - Update `noweb` engine to populate these fields. - Solve issue where `_chat` metadata was stripped during serialization, causing clients like `waha-tui` to fail filtering archived chats. --- src/core/engines/noweb/session.noweb.core.ts | 3 + src/core/engines/webjs/session.webjs.core.ts | 58 +++++++++++--------- src/structures/chats.dto.ts | 3 + 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/core/engines/noweb/session.noweb.core.ts b/src/core/engines/noweb/session.noweb.core.ts index 10c91a63e..34f0ae80c 100644 --- a/src/core/engines/noweb/session.noweb.core.ts +++ b/src/core/engines/noweb/session.noweb.core.ts @@ -1271,6 +1271,9 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { id: id, name: name || null, picture: picture, + archived: chat.archived, + pinned: (chat as any).pinned, // Cast to any if pinned is missing from type definition but exists at runtime + unreadCount: chat.unreadCount, lastMessage: message, _chat: chat, }; diff --git a/src/core/engines/webjs/session.webjs.core.ts b/src/core/engines/webjs/session.webjs.core.ts index 95bf31631..37b87dcd5 100644 --- a/src/core/engines/webjs/session.webjs.core.ts +++ b/src/core/engines/webjs/session.webjs.core.ts @@ -711,7 +711,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { const message = this.recreateMessage(messageId); const options = { // It's fine to sent just ids instead of Contact object - mentions: request.mentions as unknown as string[], + mentions: (request.mentions as unknown) as string[], linkPreview: request.linkPreview, }; return message.edit(request.text, options); @@ -900,6 +900,9 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { id: chat.id._serialized, name: chat.name || null, picture: picture, + archived: chat.archived || false, + pinned: chat.pinned || false, + unreadCount: chat.unreadCount || 0, lastMessage: lastMessage, _chat: chat, }; @@ -1652,19 +1655,23 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { filter((evt: any) => this.jids.include(evt?.after?.id?.remote || evt?.before?.id?.remote), ), - map((event): WAMessageRevokedBody => { - const afterMessage = event.after ? this.toWAMessage(event.after) : null; - const beforeMessage = event.before - ? this.toWAMessage(event.before) - : null; - // Extract the revoked message ID from the protocolMessageKey.id field - const revokedMessageId = afterMessage?._data?.protocolMessageKey?.id; - return { - after: afterMessage, - before: beforeMessage, - revokedMessageId: revokedMessageId, - }; - }), + map( + (event): WAMessageRevokedBody => { + const afterMessage = event.after + ? this.toWAMessage(event.after) + : null; + const beforeMessage = event.before + ? this.toWAMessage(event.before) + : null; + // Extract the revoked message ID from the protocolMessageKey.id field + const revokedMessageId = afterMessage?._data?.protocolMessageKey?.id; + return { + after: afterMessage, + before: beforeMessage, + revokedMessageId: revokedMessageId, + }; + }, + ), ); this.events2.get(WAHAEvents.MESSAGE_REVOKED).switch(messagesRevoked$); @@ -1685,15 +1692,17 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { ); const messagesEdit$ = messageEdit$.pipe( filter((event: any) => this.jids.include(event?.message?.id?.remote)), - map((event): WAMessageEditedBody => { - const message = this.toWAMessage(event.message); - return { - ...message, - body: event.newBody, - editedMessageId: message._data?.id?.id, - _data: event, - }; - }), + map( + (event): WAMessageEditedBody => { + const message = this.toWAMessage(event.message); + return { + ...message, + body: event.newBody, + editedMessageId: message._data?.id?.id, + _data: event, + }; + }, + ), ); this.events2.get(WAHAEvents.MESSAGE_EDITED).switch(messagesEdit$); @@ -2105,8 +2114,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { } export class WEBJSEngineMediaProcessor - implements IMediaEngineProcessor -{ + implements IMediaEngineProcessor { hasMedia(message: Message): boolean { if (!message.hasMedia) { return false; diff --git a/src/structures/chats.dto.ts b/src/structures/chats.dto.ts index 5df4a393b..55360e79d 100644 --- a/src/structures/chats.dto.ts +++ b/src/structures/chats.dto.ts @@ -230,6 +230,9 @@ export class ChatSummary { id: string; name: string | null; picture: string | null; + archived?: boolean; + pinned?: boolean; + unreadCount?: number; lastMessage: any; _chat: any; } From b50e6b2a0f2fe3c79d2a3a974265a8b35031305e Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa AKSAM Date: Sun, 21 Dec 2025 18:39:23 +0300 Subject: [PATCH 2/2] feat(chats): enhance ChatSummary DTO with additional metadata - Add isGroup, isReadOnly, timestamp, isMuted, muteExpiration properties - Update webjs engine fetchChatSummary with new fields from Chat object - Update noweb engine fetchChatSummary with equivalent fields - Update gows engine fetchChatSummary with equivalent fields This provides richer chat metadata for client applications to display pinned status, mute icons, and group indicators. --- src/core/engines/gows/session.gows.core.ts | 64 ++++++++++++-------- src/core/engines/noweb/session.noweb.core.ts | 8 ++- src/core/engines/webjs/session.webjs.core.ts | 5 ++ src/structures/chats.dto.ts | 5 ++ 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/core/engines/gows/session.gows.core.ts b/src/core/engines/gows/session.gows.core.ts index 5a9fa91eb..ebb81e716 100644 --- a/src/core/engines/gows/session.gows.core.ts +++ b/src/core/engines/gows/session.gows.core.ts @@ -509,38 +509,42 @@ export class WhatsappSessionGoWSCore extends WhatsappSession { msg?.Message?.protocolMessage?.key !== undefined ); }), - mergeMap(async (message): Promise => { - const afterMessage = await this.toWAMessage(message); - // Extract the revoked message ID from protocolMessage.key - const revokedMessageId = message.Message.protocolMessage.key?.ID; - return { - after: afterMessage, - before: null, - revokedMessageId: revokedMessageId, - _data: message, - }; - }), + mergeMap( + async (message): Promise => { + const afterMessage = await this.toWAMessage(message); + // Extract the revoked message ID from protocolMessage.key + const revokedMessageId = message.Message.protocolMessage.key?.ID; + return { + after: afterMessage, + before: null, + revokedMessageId: revokedMessageId, + _data: message, + }; + }, + ), ); this.events2.get(WAHAEvents.MESSAGE_REVOKED).switch(messagesRevoked$); // Handle edited messages const messagesEdited$ = messages$.pipe( filter((message) => IsEditedMessage(message.Message)), - mergeMap(async (message): Promise => { - const waMessage = await this.toWAMessage(message); - const content = normalizeMessageContent(message.Message); - // Extract the body from editedMessage using extractBody function - const body = extractBody(content.protocolMessage.editedMessage) || ''; - // Extract the original message ID from protocolMessage.key - // @ts-ignore - const editedMessageId = content.protocolMessage.key?.ID; - return { - ...waMessage, - body: body, - editedMessageId: editedMessageId, - _data: message, - }; - }), + mergeMap( + async (message): Promise => { + const waMessage = await this.toWAMessage(message); + const content = normalizeMessageContent(message.Message); + // Extract the body from editedMessage using extractBody function + const body = extractBody(content.protocolMessage.editedMessage) || ''; + // Extract the original message ID from protocolMessage.key + // @ts-ignore + const editedMessageId = content.protocolMessage.key?.ID; + return { + ...waMessage, + body: body, + editedMessageId: editedMessageId, + _data: message, + }; + }, + ), ); this.events2.get(WAHAEvents.MESSAGE_EDITED).switch(messagesEdited$); @@ -1844,6 +1848,14 @@ export class WhatsappSessionGoWSCore extends WhatsappSession { id: id, name: name || null, picture: picture, + isGroup: chat.id?.endsWith?.('@g.us') || false, + isReadOnly: chat.readOnly || false, + timestamp: chat.conversationTimestamp || chat.timestamp || null, + archived: chat.archived || false, + pinned: chat.pinned || false, + isMuted: chat.mute !== undefined ? chat.mute !== 0 : false, + muteExpiration: chat.mute || 0, + unreadCount: chat.unreadCount || 0, lastMessage: message, _chat: chat, }; diff --git a/src/core/engines/noweb/session.noweb.core.ts b/src/core/engines/noweb/session.noweb.core.ts index 34f0ae80c..89e9a8cd4 100644 --- a/src/core/engines/noweb/session.noweb.core.ts +++ b/src/core/engines/noweb/session.noweb.core.ts @@ -1267,12 +1267,18 @@ export class WhatsappSessionNoWebCore extends WhatsappSession { {}, ); const message = messages.length > 0 ? messages[0] : null; + const chatAny = chat as any; return { id: id, name: name || null, picture: picture, + isGroup: chat.id?.endsWith?.('@g.us') || false, + isReadOnly: chatAny.readOnly || false, + timestamp: chatAny.conversationTimestamp || chatAny.t || null, archived: chat.archived, - pinned: (chat as any).pinned, // Cast to any if pinned is missing from type definition but exists at runtime + pinned: chatAny.pinned || chatAny.pin || false, + isMuted: chatAny.mute !== undefined ? chatAny.mute !== 0 : false, + muteExpiration: chatAny.mute || 0, unreadCount: chat.unreadCount, lastMessage: message, _chat: chat, diff --git a/src/core/engines/webjs/session.webjs.core.ts b/src/core/engines/webjs/session.webjs.core.ts index 37b87dcd5..f596020d9 100644 --- a/src/core/engines/webjs/session.webjs.core.ts +++ b/src/core/engines/webjs/session.webjs.core.ts @@ -900,8 +900,13 @@ export class WhatsappSessionWebJSCore extends WhatsappSession { id: chat.id._serialized, name: chat.name || null, picture: picture, + isGroup: chat.isGroup || false, + isReadOnly: chat.isReadOnly || false, + timestamp: chat.timestamp || null, archived: chat.archived || false, pinned: chat.pinned || false, + isMuted: chat.isMuted || false, + muteExpiration: chat.muteExpiration || 0, unreadCount: chat.unreadCount || 0, lastMessage: lastMessage, _chat: chat, diff --git a/src/structures/chats.dto.ts b/src/structures/chats.dto.ts index 55360e79d..3722bc17c 100644 --- a/src/structures/chats.dto.ts +++ b/src/structures/chats.dto.ts @@ -230,8 +230,13 @@ export class ChatSummary { id: string; name: string | null; picture: string | null; + isGroup?: boolean; + isReadOnly?: boolean; + timestamp?: number; archived?: boolean; pinned?: boolean; + isMuted?: boolean; + muteExpiration?: number; unreadCount?: number; lastMessage: any; _chat: any;