Compare commits

...
11 Commits
Author SHA1 Message Date
devlikepro d66c80f95a [core] 2025.8.3
Release / WEBJS - chrome - amd64 - chrome (push) Waiting to run
Release / WEBJS - chromium - amd64 - latest (push) Waiting to run
Release / WEBJS - chromium - linux/arm64 - arm (push) Waiting to run
Release / GOWS - none - amd64 - gows (push) Waiting to run
Release / GOWS - none - linux/arm64 - gows-arm (push) Waiting to run
Release / NOWEB - none - amd64 - noweb (push) Waiting to run
Release / NOWEB - none - linux/arm64 - noweb-arm (push) Waiting to run
2025-08-30 18:30:07 +07:00
devlikepro 26f04bbd94 [core] Up Dashboard 2025-08-30 18:30:06 +07:00
devlikepro 6582c03823 [core] Up GOWS 2025-08-30 18:30:06 +07:00
devlikepro abacaf2e02 [core] WEBJS - fix STARTING session
fix #1298
fix #1299
fix #1300
2025-08-30 18:30:05 +07:00
devlikepro c65d8b9856 [core] GOWS - chat /unread 2025-08-30 18:30:05 +07:00
devlikepro 8f94cf06de [core] WEBJS - add webjs.tagsEventsOn config 2025-08-30 18:30:04 +07:00
devlikepro 94c1c16de8 [core] Use oxlint instead of eslint 2025-08-30 18:30:03 +07:00
devlikepro e69d992725 [core] Ignore - Status, Groups, Broadcast
fix #1142
fix #1259
fix #1190
2025-08-30 18:30:03 +07:00
devlikepro e6c5dd6e22 [core] eslint - no project 2025-08-30 18:30:02 +07:00
devlikepro 5486d4874a [core] Refactor media and processIncomingMessage 2025-08-30 18:30:02 +07:00
devlikepro 9d9d8e03fe [core] Add @types 2025-08-30 18:30:02 +07:00
27 changed files with 1362 additions and 1635 deletions

No files matched your search

+1
View File
@@ -1,2 +1,3 @@
src/core/engines/gows/grpc/*
src/core/engines/gows/proto/*
src/core/engines/webjs/_lodash.js
-36
View File
@@ -1,36 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin', 'simple-import-sort'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
],
root: true,
env: {
node: true,
jest: true,
},
rules: {
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'lines-between-class-members': [
'error',
'always',
{ exceptAfterSingleLine: true },
],
},
};
+15
View File
@@ -0,0 +1,15 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript"],
"env": {
"builtin": true
},
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",
"no-unused-vars": "off"
}
}
+5 -11
View File
@@ -17,18 +17,12 @@ repos:
language: python
stages: [commit-msg]
- repo: local
hooks:
- id: lint
stages: [pre-commit]
name: lint
- id: oxlint
name: oxlint
entry: npx oxlint --fix --deny-warnings
language: system
entry: bash -c '$HOME/.nvm/nvm-exec npm run lint-cache'
pass_filenames: false
files: |
(?x)^(
src/.*|
)$
pass_filenames: true
files: \.(ts|tsx|js|jsx)$
- repo: https://github.com/pre-commit/mirrors-prettier
rev: 'v3.1.0'
+5 -8
View File
@@ -14,8 +14,8 @@
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"start:prod-exit": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --max-warnings=0",
"lint-cache": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix --cache --max-warnings=0",
"lint": "oxlint --deny-warnings",
"lint-fix": "oxlint --fix --deny-warnings",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
@@ -124,15 +124,12 @@
"@types/express": "^4.17.3",
"@types/jest": "26.0.10",
"@types/node": "^18.14.2",
"@types/node-fetch": "^2.6.13",
"@types/semver": "^7.7.0",
"@types/supertest": "^2.0.8",
"@typescript-eslint/eslint-plugin": "3.9.1",
"@typescript-eslint/parser": "3.9.1",
"eslint": "7.7.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"grpc-tools": "^1.13.0",
"jest": "^29.7.0",
"oxlint": "^1.13.0",
"prettier": "^1.19.1",
"protoc-gen-ts": "^0.8.7",
"supertest": "^4.0.2",
+1 -1
View File
@@ -20,7 +20,7 @@ export function MarkdownToWhatsApp(text: string): string {
// Links: [text](url) → text (url)
.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '$1 ($2)')
// Lists: -, +, * → * item
.replace(/^[\-\+\*] (.*)/gm, '* $1')
.replace(/^[-+*] (.*)/gm, '* $1')
);
}
+18
View File
@@ -1,6 +1,7 @@
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { GlobalWebhookConfigConfig } from '@waha/core/config/GlobalWebhookConfig';
import { IgnoreJidConfig } from '@waha/core/utils/jids';
import { parseBool } from './helpers';
import { WebhookConfig } from './structures/webhooks.config.dto';
@@ -178,6 +179,23 @@ export class WhatsappConfigService implements OnApplicationBootstrap {
return parseBool(value);
}
/**
* Global default "ignore settings" for chats.
* If not defined, defaults to false (do not ignore anything).
*/
getIgnoreChatsConfig(): IgnoreJidConfig {
const status = parseBool(
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_STATUS', 'false'),
);
const groups = parseBool(
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_GROUPS', 'false'),
);
const channels = parseBool(
this.configService.get('WAHA_SESSION_CONFIG_IGNORE_CHANNELS', 'false'),
);
return { status, groups, channels };
}
onApplicationBootstrap() {
const error = this.webhookConfig.validateConfig();
if (error) {
+8
View File
@@ -14,9 +14,11 @@ import { GowsEngineConfigService } from '@waha/core/config/GowsEngineConfigServi
import { GowsBootstrap } from '@waha/core/engines/gows/GowsBootstrap';
import { ISessionMeRepository } from '@waha/core/storage/ISessionMeRepository';
import { ISessionWorkerRepository } from '@waha/core/storage/ISessionWorkerRepository';
import { IgnoreJidConfig } from '@waha/core/utils/jids';
import { WAHAWebhook } from '@waha/structures/webhooks.dto';
import { waitUntil } from '@waha/utils/promiseTimeout';
import { VERSION } from '@waha/version';
import * as lodash from 'lodash';
import { PinoLogger } from 'nestjs-pino';
import { merge, Observable, of } from 'rxjs';
@@ -235,6 +237,12 @@ export abstract class SessionManager
}
return new NoopEngineBootstrap();
}
protected ignoreChatsConfig(config: SessionConfig) {
const ignore: IgnoreJidConfig = this.config.getIgnoreChatsConfig();
// Given the default, overwrite from the config if any
return lodash.defaults({}, config?.ignore, ignore);
}
}
export function populateSessionInfo(
+16 -5
View File
@@ -4,7 +4,11 @@ import {
IMediaConverter,
} from '@waha/core/media/IConverter';
import { MessagesForRead } from '@waha/core/utils/convertors';
import { isJidNewsletter } from '@waha/core/utils/jids';
import {
IgnoreJidConfig,
isJidNewsletter,
JidFilter,
} from '@waha/core/utils/jids';
import {
Channel,
ChannelListResult,
@@ -90,10 +94,7 @@ import {
WAHAPresenceStatus,
WAHASessionStatus,
} from '../../structures/enums.dto';
import {
EventCancelRequest,
EventMessageRequest,
} from '../../structures/events.dto';
import { EventMessageRequest } from '../../structures/events.dto';
import {
CreateGroupRequest,
GroupField,
@@ -153,8 +154,11 @@ export interface SessionParams {
loggerBuilder: LoggerBuilder;
sessionStore: DataStore;
proxyConfig?: ProxyConfig;
// Raw unchanged SessionConfig
sessionConfig?: SessionConfig;
engineConfig?: any;
// Ignore settings
ignore: IgnoreJidConfig;
}
export abstract class WhatsappSession {
@@ -169,6 +173,7 @@ export abstract class WhatsappSession {
public sessionConfig?: SessionConfig;
protected engineConfig?: any;
protected unpairing: boolean = false;
protected jids: JidFilter;
private _status: WAHASessionStatus;
private shouldPrintQR: boolean;
@@ -195,6 +200,7 @@ export abstract class WhatsappSession {
mediaManager,
sessionConfig,
engineConfig,
ignore,
}: SessionParams) {
this.status$ = new BehaviorSubject(null);
@@ -260,6 +266,11 @@ export abstract class WhatsappSession {
this.sessionConfig = sessionConfig;
this.engineConfig = engineConfig;
this.shouldPrintQR = printQR;
this.logger.info(
{ ignore: ignore },
'The session ignores the following chat ids',
);
this.jids = new JidFilter(ignore);
}
public getEventObservable(event: WAHAEvents) {
+1 -3
View File
@@ -32,9 +32,7 @@ export class HashAuth implements IApiKeyAuth {
constructor(
private hash: string,
private algorithm: string,
) {
this.algorithm = algorithm;
}
) {}
isValid(plain: string): boolean {
if (!plain) {
+280 -2
View File
@@ -1302,13 +1302,128 @@ export namespace messages {
return SessionProxyConfig.deserialize(bytes);
}
}
export class SessionConfig extends pb_1.Message {
export class SessionIgnoreJidsConfig extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(data?: any[] | {
status?: boolean;
groups?: boolean;
newsletters?: boolean;
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
if (!Array.isArray(data) && typeof data == "object") {
if ("status" in data && data.status != undefined) {
this.status = data.status;
}
if ("groups" in data && data.groups != undefined) {
this.groups = data.groups;
}
if ("newsletters" in data && data.newsletters != undefined) {
this.newsletters = data.newsletters;
}
}
}
get status() {
return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean;
}
set status(value: boolean) {
pb_1.Message.setField(this, 1, value);
}
get groups() {
return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean;
}
set groups(value: boolean) {
pb_1.Message.setField(this, 2, value);
}
get newsletters() {
return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean;
}
set newsletters(value: boolean) {
pb_1.Message.setField(this, 3, value);
}
static fromObject(data: {
status?: boolean;
groups?: boolean;
newsletters?: boolean;
}): SessionIgnoreJidsConfig {
const message = new SessionIgnoreJidsConfig({});
if (data.status != null) {
message.status = data.status;
}
if (data.groups != null) {
message.groups = data.groups;
}
if (data.newsletters != null) {
message.newsletters = data.newsletters;
}
return message;
}
toObject() {
const data: {
status?: boolean;
groups?: boolean;
newsletters?: boolean;
} = {};
if (this.status != null) {
data.status = this.status;
}
if (this.groups != null) {
data.groups = this.groups;
}
if (this.newsletters != null) {
data.newsletters = this.newsletters;
}
return data;
}
serialize(): Uint8Array;
serialize(w: pb_1.BinaryWriter): void;
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
const writer = w || new pb_1.BinaryWriter();
if (this.status != false)
writer.writeBool(1, this.status);
if (this.groups != false)
writer.writeBool(2, this.groups);
if (this.newsletters != false)
writer.writeBool(3, this.newsletters);
if (!w)
return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): SessionIgnoreJidsConfig {
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new SessionIgnoreJidsConfig();
while (reader.nextField()) {
if (reader.isEndGroup())
break;
switch (reader.getFieldNumber()) {
case 1:
message.status = reader.readBool();
break;
case 2:
message.groups = reader.readBool();
break;
case 3:
message.newsletters = reader.readBool();
break;
default: reader.skipField();
}
}
return message;
}
serializeBinary(): Uint8Array {
return this.serialize();
}
static deserializeBinary(bytes: Uint8Array): SessionIgnoreJidsConfig {
return SessionIgnoreJidsConfig.deserialize(bytes);
}
}
export class SessionConfig extends pb_1.Message {
#one_of_decls: number[][] = [[4]];
constructor(data?: any[] | ({
store?: SessionStoreConfig;
log?: SessionLogConfig;
proxy?: SessionProxyConfig;
}) {
} & (({
ignore?: SessionIgnoreJidsConfig;
})))) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
if (!Array.isArray(data) && typeof data == "object") {
@@ -1321,6 +1436,9 @@ export namespace messages {
if ("proxy" in data && data.proxy != undefined) {
this.proxy = data.proxy;
}
if ("ignore" in data && data.ignore != undefined) {
this.ignore = data.ignore;
}
}
}
get store() {
@@ -1350,10 +1468,29 @@ export namespace messages {
get has_proxy() {
return pb_1.Message.getField(this, 3) != null;
}
get ignore() {
return pb_1.Message.getWrapperField(this, SessionIgnoreJidsConfig, 4) as SessionIgnoreJidsConfig;
}
set ignore(value: SessionIgnoreJidsConfig) {
pb_1.Message.setOneofWrapperField(this, 4, this.#one_of_decls[0], value);
}
get has_ignore() {
return pb_1.Message.getField(this, 4) != null;
}
get _ignore() {
const cases: {
[index: number]: "none" | "ignore";
} = {
0: "none",
4: "ignore"
};
return cases[pb_1.Message.computeOneofCase(this, [4])];
}
static fromObject(data: {
store?: ReturnType<typeof SessionStoreConfig.prototype.toObject>;
log?: ReturnType<typeof SessionLogConfig.prototype.toObject>;
proxy?: ReturnType<typeof SessionProxyConfig.prototype.toObject>;
ignore?: ReturnType<typeof SessionIgnoreJidsConfig.prototype.toObject>;
}): SessionConfig {
const message = new SessionConfig({});
if (data.store != null) {
@@ -1365,6 +1502,9 @@ export namespace messages {
if (data.proxy != null) {
message.proxy = SessionProxyConfig.fromObject(data.proxy);
}
if (data.ignore != null) {
message.ignore = SessionIgnoreJidsConfig.fromObject(data.ignore);
}
return message;
}
toObject() {
@@ -1372,6 +1512,7 @@ export namespace messages {
store?: ReturnType<typeof SessionStoreConfig.prototype.toObject>;
log?: ReturnType<typeof SessionLogConfig.prototype.toObject>;
proxy?: ReturnType<typeof SessionProxyConfig.prototype.toObject>;
ignore?: ReturnType<typeof SessionIgnoreJidsConfig.prototype.toObject>;
} = {};
if (this.store != null) {
data.store = this.store.toObject();
@@ -1382,6 +1523,9 @@ export namespace messages {
if (this.proxy != null) {
data.proxy = this.proxy.toObject();
}
if (this.ignore != null) {
data.ignore = this.ignore.toObject();
}
return data;
}
serialize(): Uint8Array;
@@ -1394,6 +1538,8 @@ export namespace messages {
writer.writeMessage(2, this.log, () => this.log.serialize(writer));
if (this.has_proxy)
writer.writeMessage(3, this.proxy, () => this.proxy.serialize(writer));
if (this.has_ignore)
writer.writeMessage(4, this.ignore, () => this.ignore.serialize(writer));
if (!w)
return writer.getResultBuffer();
}
@@ -1412,6 +1558,9 @@ export namespace messages {
case 3:
reader.readMessage(message.proxy, () => message.proxy = SessionProxyConfig.deserialize(reader));
break;
case 4:
reader.readMessage(message.ignore, () => message.ignore = SessionIgnoreJidsConfig.deserialize(reader));
break;
default: reader.skipField();
}
}
@@ -5507,6 +5656,122 @@ export namespace messages {
return CheckPhonesRequest.deserialize(bytes);
}
}
export class ChatUnreadRequest extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(data?: any[] | {
session?: Session;
jid?: string;
read?: boolean;
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
if (!Array.isArray(data) && typeof data == "object") {
if ("session" in data && data.session != undefined) {
this.session = data.session;
}
if ("jid" in data && data.jid != undefined) {
this.jid = data.jid;
}
if ("read" in data && data.read != undefined) {
this.read = data.read;
}
}
}
get session() {
return pb_1.Message.getWrapperField(this, Session, 1) as Session;
}
set session(value: Session) {
pb_1.Message.setWrapperField(this, 1, value);
}
get has_session() {
return pb_1.Message.getField(this, 1) != null;
}
get jid() {
return pb_1.Message.getFieldWithDefault(this, 2, "") as string;
}
set jid(value: string) {
pb_1.Message.setField(this, 2, value);
}
get read() {
return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean;
}
set read(value: boolean) {
pb_1.Message.setField(this, 3, value);
}
static fromObject(data: {
session?: ReturnType<typeof Session.prototype.toObject>;
jid?: string;
read?: boolean;
}): ChatUnreadRequest {
const message = new ChatUnreadRequest({});
if (data.session != null) {
message.session = Session.fromObject(data.session);
}
if (data.jid != null) {
message.jid = data.jid;
}
if (data.read != null) {
message.read = data.read;
}
return message;
}
toObject() {
const data: {
session?: ReturnType<typeof Session.prototype.toObject>;
jid?: string;
read?: boolean;
} = {};
if (this.session != null) {
data.session = this.session.toObject();
}
if (this.jid != null) {
data.jid = this.jid;
}
if (this.read != null) {
data.read = this.read;
}
return data;
}
serialize(): Uint8Array;
serialize(w: pb_1.BinaryWriter): void;
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
const writer = w || new pb_1.BinaryWriter();
if (this.has_session)
writer.writeMessage(1, this.session, () => this.session.serialize(writer));
if (this.jid.length)
writer.writeString(2, this.jid);
if (this.read != false)
writer.writeBool(3, this.read);
if (!w)
return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): ChatUnreadRequest {
const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new ChatUnreadRequest();
while (reader.nextField()) {
if (reader.isEndGroup())
break;
switch (reader.getFieldNumber()) {
case 1:
reader.readMessage(message.session, () => message.session = Session.deserialize(reader));
break;
case 2:
message.jid = reader.readString();
break;
case 3:
message.read = reader.readBool();
break;
default: reader.skipField();
}
}
return message;
}
serializeBinary(): Uint8Array {
return this.serialize();
}
static deserializeBinary(bytes: Uint8Array): ChatUnreadRequest {
return ChatUnreadRequest.deserialize(bytes);
}
}
export class PhoneInfo extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(data?: any[] | {
@@ -10275,6 +10540,15 @@ export namespace messages {
responseSerialize: (message: CheckPhonesResponse) => Buffer.from(message.serialize()),
responseDeserialize: (bytes: Buffer) => CheckPhonesResponse.deserialize(new Uint8Array(bytes))
},
MarkChatUnread: {
path: "/messages.MessageService/MarkChatUnread",
requestStream: false,
responseStream: false,
requestSerialize: (message: ChatUnreadRequest) => Buffer.from(message.serialize()),
requestDeserialize: (bytes: Buffer) => ChatUnreadRequest.deserialize(new Uint8Array(bytes)),
responseSerialize: (message: Empty) => Buffer.from(message.serialize()),
responseDeserialize: (bytes: Buffer) => Empty.deserialize(new Uint8Array(bytes))
},
GenerateNewMessageID: {
path: "/messages.MessageService/GenerateNewMessageID",
requestStream: false,
@@ -10579,6 +10853,7 @@ export namespace messages {
abstract SendChatPresence(call: grpc_1.ServerUnaryCall<ChatPresenceRequest, Empty>, callback: grpc_1.sendUnaryData<Empty>): void;
abstract SubscribePresence(call: grpc_1.ServerUnaryCall<SubscribePresenceRequest, Empty>, callback: grpc_1.sendUnaryData<Empty>): void;
abstract CheckPhones(call: grpc_1.ServerUnaryCall<CheckPhonesRequest, CheckPhonesResponse>, callback: grpc_1.sendUnaryData<CheckPhonesResponse>): void;
abstract MarkChatUnread(call: grpc_1.ServerUnaryCall<ChatUnreadRequest, Empty>, callback: grpc_1.sendUnaryData<Empty>): void;
abstract GenerateNewMessageID(call: grpc_1.ServerUnaryCall<Session, NewMessageIDResponse>, callback: grpc_1.sendUnaryData<NewMessageIDResponse>): void;
abstract SendMessage(call: grpc_1.ServerUnaryCall<MessageRequest, MessageResponse>, callback: grpc_1.sendUnaryData<MessageResponse>): void;
abstract SendReaction(call: grpc_1.ServerUnaryCall<MessageReaction, MessageResponse>, callback: grpc_1.sendUnaryData<MessageResponse>): void;
@@ -10710,6 +10985,9 @@ export namespace messages {
CheckPhones: GrpcUnaryServiceInterface<CheckPhonesRequest, CheckPhonesResponse> = (message: CheckPhonesRequest, metadata: grpc_1.Metadata | grpc_1.CallOptions | grpc_1.requestCallback<CheckPhonesResponse>, options?: grpc_1.CallOptions | grpc_1.requestCallback<CheckPhonesResponse>, callback?: grpc_1.requestCallback<CheckPhonesResponse>): grpc_1.ClientUnaryCall => {
return super.CheckPhones(message, metadata, options, callback);
};
MarkChatUnread: GrpcUnaryServiceInterface<ChatUnreadRequest, Empty> = (message: ChatUnreadRequest, metadata: grpc_1.Metadata | grpc_1.CallOptions | grpc_1.requestCallback<Empty>, options?: grpc_1.CallOptions | grpc_1.requestCallback<Empty>, callback?: grpc_1.requestCallback<Empty>): grpc_1.ClientUnaryCall => {
return super.MarkChatUnread(message, metadata, options, callback);
};
GenerateNewMessageID: GrpcUnaryServiceInterface<Session, NewMessageIDResponse> = (message: Session, metadata: grpc_1.Metadata | grpc_1.CallOptions | grpc_1.requestCallback<NewMessageIDResponse>, options?: grpc_1.CallOptions | grpc_1.requestCallback<NewMessageIDResponse>, callback?: grpc_1.requestCallback<NewMessageIDResponse>): grpc_1.ClientUnaryCall => {
return super.GenerateNewMessageID(message, metadata, options, callback);
};
@@ -48,6 +48,17 @@ function deserialize_messages_ChatPresenceRequest(buffer_arg) {
return gows_pb.ChatPresenceRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_messages_ChatUnreadRequest(arg) {
if (!(arg instanceof gows_pb.ChatUnreadRequest)) {
throw new Error('Expected argument of type messages.ChatUnreadRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_messages_ChatUnreadRequest(buffer_arg) {
return gows_pb.ChatUnreadRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_messages_CheckPhonesRequest(arg) {
if (!(arg instanceof gows_pb.CheckPhonesRequest)) {
throw new Error('Expected argument of type messages.CheckPhonesRequest');
@@ -1053,6 +1064,17 @@ getProfilePicture: {
responseSerialize: serialize_messages_CheckPhonesResponse,
responseDeserialize: deserialize_messages_CheckPhonesResponse,
},
markChatUnread: {
path: '/messages.MessageService/MarkChatUnread',
requestStream: false,
responseStream: false,
requestType: gows_pb.ChatUnreadRequest,
responseType: gows_pb.Empty,
requestSerialize: serialize_messages_ChatUnreadRequest,
requestDeserialize: deserialize_messages_ChatUnreadRequest,
responseSerialize: serialize_messages_Empty,
responseDeserialize: deserialize_messages_Empty,
},
//
// Message
//
+497 -1
View File
@@ -28,6 +28,7 @@ goog.exportSymbol('proto.messages.ChatFilter', null, global);
goog.exportSymbol('proto.messages.ChatLabelRequest', null, global);
goog.exportSymbol('proto.messages.ChatPresence', null, global);
goog.exportSymbol('proto.messages.ChatPresenceRequest', null, global);
goog.exportSymbol('proto.messages.ChatUnreadRequest', null, global);
goog.exportSymbol('proto.messages.CheckPhonesRequest', null, global);
goog.exportSymbol('proto.messages.CheckPhonesResponse', null, global);
goog.exportSymbol('proto.messages.CreateGroupRequest', null, global);
@@ -102,6 +103,7 @@ goog.exportSymbol('proto.messages.SearchPageResult', null, global);
goog.exportSymbol('proto.messages.Section', null, global);
goog.exportSymbol('proto.messages.Session', null, global);
goog.exportSymbol('proto.messages.SessionConfig', null, global);
goog.exportSymbol('proto.messages.SessionIgnoreJidsConfig', null, global);
goog.exportSymbol('proto.messages.SessionLogConfig', null, global);
goog.exportSymbol('proto.messages.SessionProxyConfig', null, global);
goog.exportSymbol('proto.messages.SessionStateResponse', null, global);
@@ -452,6 +454,27 @@ if (goog.DEBUG && !COMPILED) {
*/
proto.messages.SessionProxyConfig.displayName = 'proto.messages.SessionProxyConfig';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.messages.SessionIgnoreJidsConfig = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.messages.SessionIgnoreJidsConfig, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.messages.SessionIgnoreJidsConfig.displayName = 'proto.messages.SessionIgnoreJidsConfig';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
@@ -1145,6 +1168,27 @@ if (goog.DEBUG && !COMPILED) {
*/
proto.messages.CheckPhonesRequest.displayName = 'proto.messages.CheckPhonesRequest';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.messages.ChatUnreadRequest = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.messages.ChatUnreadRequest, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.messages.ChatUnreadRequest.displayName = 'proto.messages.ChatUnreadRequest';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
@@ -4372,6 +4416,196 @@ proto.messages.SessionProxyConfig.prototype.setUrl = function(value) {
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.messages.SessionIgnoreJidsConfig.prototype.toObject = function(opt_includeInstance) {
return proto.messages.SessionIgnoreJidsConfig.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.messages.SessionIgnoreJidsConfig} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.messages.SessionIgnoreJidsConfig.toObject = function(includeInstance, msg) {
var f, obj = {
status: jspb.Message.getBooleanFieldWithDefault(msg, 1, false),
groups: jspb.Message.getBooleanFieldWithDefault(msg, 2, false),
newsletters: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.messages.SessionIgnoreJidsConfig}
*/
proto.messages.SessionIgnoreJidsConfig.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.messages.SessionIgnoreJidsConfig;
return proto.messages.SessionIgnoreJidsConfig.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.messages.SessionIgnoreJidsConfig} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.messages.SessionIgnoreJidsConfig}
*/
proto.messages.SessionIgnoreJidsConfig.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {boolean} */ (reader.readBool());
msg.setStatus(value);
break;
case 2:
var value = /** @type {boolean} */ (reader.readBool());
msg.setGroups(value);
break;
case 3:
var value = /** @type {boolean} */ (reader.readBool());
msg.setNewsletters(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.messages.SessionIgnoreJidsConfig.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.messages.SessionIgnoreJidsConfig.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.messages.SessionIgnoreJidsConfig} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.messages.SessionIgnoreJidsConfig.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getStatus();
if (f) {
writer.writeBool(
1,
f
);
}
f = message.getGroups();
if (f) {
writer.writeBool(
2,
f
);
}
f = message.getNewsletters();
if (f) {
writer.writeBool(
3,
f
);
}
};
/**
* optional bool status = 1;
* @return {boolean}
*/
proto.messages.SessionIgnoreJidsConfig.prototype.getStatus = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false));
};
/**
* @param {boolean} value
* @return {!proto.messages.SessionIgnoreJidsConfig} returns this
*/
proto.messages.SessionIgnoreJidsConfig.prototype.setStatus = function(value) {
return jspb.Message.setProto3BooleanField(this, 1, value);
};
/**
* optional bool groups = 2;
* @return {boolean}
*/
proto.messages.SessionIgnoreJidsConfig.prototype.getGroups = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false));
};
/**
* @param {boolean} value
* @return {!proto.messages.SessionIgnoreJidsConfig} returns this
*/
proto.messages.SessionIgnoreJidsConfig.prototype.setGroups = function(value) {
return jspb.Message.setProto3BooleanField(this, 2, value);
};
/**
* optional bool newsletters = 3;
* @return {boolean}
*/
proto.messages.SessionIgnoreJidsConfig.prototype.getNewsletters = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
};
/**
* @param {boolean} value
* @return {!proto.messages.SessionIgnoreJidsConfig} returns this
*/
proto.messages.SessionIgnoreJidsConfig.prototype.setNewsletters = function(value) {
return jspb.Message.setProto3BooleanField(this, 3, value);
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
@@ -4403,7 +4637,8 @@ proto.messages.SessionConfig.toObject = function(includeInstance, msg) {
var f, obj = {
store: (f = msg.getStore()) && proto.messages.SessionStoreConfig.toObject(includeInstance, f),
log: (f = msg.getLog()) && proto.messages.SessionLogConfig.toObject(includeInstance, f),
proxy: (f = msg.getProxy()) && proto.messages.SessionProxyConfig.toObject(includeInstance, f)
proxy: (f = msg.getProxy()) && proto.messages.SessionProxyConfig.toObject(includeInstance, f),
ignore: (f = msg.getIgnore()) && proto.messages.SessionIgnoreJidsConfig.toObject(includeInstance, f)
};
if (includeInstance) {
@@ -4455,6 +4690,11 @@ proto.messages.SessionConfig.deserializeBinaryFromReader = function(msg, reader)
reader.readMessage(value,proto.messages.SessionProxyConfig.deserializeBinaryFromReader);
msg.setProxy(value);
break;
case 4:
var value = new proto.messages.SessionIgnoreJidsConfig;
reader.readMessage(value,proto.messages.SessionIgnoreJidsConfig.deserializeBinaryFromReader);
msg.setIgnore(value);
break;
default:
reader.skipField();
break;
@@ -4508,6 +4748,14 @@ proto.messages.SessionConfig.serializeBinaryToWriter = function(message, writer)
proto.messages.SessionProxyConfig.serializeBinaryToWriter
);
}
f = message.getIgnore();
if (f != null) {
writer.writeMessage(
4,
f,
proto.messages.SessionIgnoreJidsConfig.serializeBinaryToWriter
);
}
};
@@ -4622,6 +4870,43 @@ proto.messages.SessionConfig.prototype.hasProxy = function() {
};
/**
* optional SessionIgnoreJidsConfig ignore = 4;
* @return {?proto.messages.SessionIgnoreJidsConfig}
*/
proto.messages.SessionConfig.prototype.getIgnore = function() {
return /** @type{?proto.messages.SessionIgnoreJidsConfig} */ (
jspb.Message.getWrapperField(this, proto.messages.SessionIgnoreJidsConfig, 4));
};
/**
* @param {?proto.messages.SessionIgnoreJidsConfig|undefined} value
* @return {!proto.messages.SessionConfig} returns this
*/
proto.messages.SessionConfig.prototype.setIgnore = function(value) {
return jspb.Message.setWrapperField(this, 4, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.messages.SessionConfig} returns this
*/
proto.messages.SessionConfig.prototype.clearIgnore = function() {
return this.setIgnore(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.messages.SessionConfig.prototype.hasIgnore = function() {
return jspb.Message.getField(this, 4) != null;
};
@@ -12151,6 +12436,217 @@ proto.messages.CheckPhonesRequest.prototype.clearPhonesList = function() {
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.messages.ChatUnreadRequest.prototype.toObject = function(opt_includeInstance) {
return proto.messages.ChatUnreadRequest.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.messages.ChatUnreadRequest} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.messages.ChatUnreadRequest.toObject = function(includeInstance, msg) {
var f, obj = {
session: (f = msg.getSession()) && proto.messages.Session.toObject(includeInstance, f),
jid: jspb.Message.getFieldWithDefault(msg, 2, ""),
read: jspb.Message.getBooleanFieldWithDefault(msg, 3, false)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.messages.ChatUnreadRequest}
*/
proto.messages.ChatUnreadRequest.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.messages.ChatUnreadRequest;
return proto.messages.ChatUnreadRequest.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.messages.ChatUnreadRequest} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.messages.ChatUnreadRequest}
*/
proto.messages.ChatUnreadRequest.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = new proto.messages.Session;
reader.readMessage(value,proto.messages.Session.deserializeBinaryFromReader);
msg.setSession(value);
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setJid(value);
break;
case 3:
var value = /** @type {boolean} */ (reader.readBool());
msg.setRead(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.messages.ChatUnreadRequest.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.messages.ChatUnreadRequest.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.messages.ChatUnreadRequest} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.messages.ChatUnreadRequest.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getSession();
if (f != null) {
writer.writeMessage(
1,
f,
proto.messages.Session.serializeBinaryToWriter
);
}
f = message.getJid();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = message.getRead();
if (f) {
writer.writeBool(
3,
f
);
}
};
/**
* optional Session session = 1;
* @return {?proto.messages.Session}
*/
proto.messages.ChatUnreadRequest.prototype.getSession = function() {
return /** @type{?proto.messages.Session} */ (
jspb.Message.getWrapperField(this, proto.messages.Session, 1));
};
/**
* @param {?proto.messages.Session|undefined} value
* @return {!proto.messages.ChatUnreadRequest} returns this
*/
proto.messages.ChatUnreadRequest.prototype.setSession = function(value) {
return jspb.Message.setWrapperField(this, 1, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.messages.ChatUnreadRequest} returns this
*/
proto.messages.ChatUnreadRequest.prototype.clearSession = function() {
return this.setSession(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.messages.ChatUnreadRequest.prototype.hasSession = function() {
return jspb.Message.getField(this, 1) != null;
};
/**
* optional string jid = 2;
* @return {string}
*/
proto.messages.ChatUnreadRequest.prototype.getJid = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/**
* @param {string} value
* @return {!proto.messages.ChatUnreadRequest} returns this
*/
proto.messages.ChatUnreadRequest.prototype.setJid = function(value) {
return jspb.Message.setProto3StringField(this, 2, value);
};
/**
* optional bool read = 3;
* @return {boolean}
*/
proto.messages.ChatUnreadRequest.prototype.getRead = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
};
/**
* @param {boolean} value
* @return {!proto.messages.ChatUnreadRequest} returns this
*/
proto.messages.ChatUnreadRequest.prototype.setRead = function(value) {
return jspb.Message.setProto3BooleanField(this, 3, value);
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
+67 -17
View File
@@ -254,6 +254,11 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
proxy: new messages.SessionProxyConfig({
url: this.getProxyUrl(this.proxyConfig),
}),
ignore: new messages.SessionIgnoreJidsConfig({
status: this.jids.ignore.status,
groups: this.jids.ignore.groups,
newsletters: this.jids.ignore.channels,
}),
}),
});
@@ -391,7 +396,11 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
const all$ = this.all$;
this.events2.get(WAHAEvents.ENGINE_EVENT).switch(all$);
const messages$ = all$.pipe(onlyEvent(WhatsMeowEvent.MESSAGE));
const messages$ = all$.pipe(
onlyEvent(WhatsMeowEvent.MESSAGE),
filter((msg: any) => this.jids.include(msg?.Info?.Chat)),
share(),
);
let [messagesFromMe$, messagesFromOthers$] = partition(messages$, isMine);
messagesFromMe$ = messagesFromMe$.pipe(
@@ -461,7 +470,10 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
);
this.events2.get(WAHAEvents.MESSAGE_EDITED).switch(messagesEdited$);
const receipt$ = all$.pipe(onlyEvent(WhatsMeowEvent.RECEIPT));
const receipt$ = all$.pipe(
onlyEvent(WhatsMeowEvent.RECEIPT),
filter((r: any) => this.jids.include(r?.Chat)),
);
const messageAck$ = receipt$.pipe(
mergeMap(this.receiptToMessageAck.bind(this)),
DistinctAck(),
@@ -476,9 +488,13 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
const presence$ = all$.pipe(
onlyEvent(WhatsMeowEvent.PRESENCE),
filter((event: any) => this.jids.include(event?.From)),
filter((event) => !isJidGroup(event.From)),
);
const chatPresence$ = all$.pipe(onlyEvent(WhatsMeowEvent.CHAT_PRESENCE));
const chatPresence$ = all$.pipe(
onlyEvent(WhatsMeowEvent.CHAT_PRESENCE),
filter((event: any) => this.jids.include(event?.Chat)),
);
const presenceUpdates$ = merge(presence$, chatPresence$).pipe(
map((event) => this.toWahaPresences(event.From || event.Chat, [event])),
);
@@ -538,6 +554,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
//
const pollVoteEvent$ = all$.pipe(
onlyEvent(WhatsMeowEvent.POLL_VOTE_EVENT),
filter((event: any) => this.jids.include(event?.Info?.Chat)),
map(this.toPollVotePayload.bind(this)),
filter(Boolean),
share(),
@@ -557,6 +574,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
//
const eventMessageResponse$ = all$.pipe(
onlyEvent(WhatsMeowEvent.EVENT_MESSAGE_RESPONSE),
filter((event: any) => this.jids.include(event?.Info?.Chat)),
map(this.toEventResponsePayload.bind(this)),
filter(Boolean),
);
@@ -1841,6 +1859,17 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
return labels.map(this.toLabel);
}
public async chatsUnreadChat(chatId: string): Promise<any> {
const jid = toJID(this.ensureSuffix(chatId));
const request = new messages.ChatUnreadRequest({
session: this.session,
jid: jid,
read: false,
});
await promisify(this.client.MarkChatUnread)(request);
return { success: true };
}
public async putLabelsToChat(chatId: string, labels: LabelID[]) {
const jid = toJID(chatId);
const labelsIds = labels.map((label) => label.id);
@@ -1870,7 +1899,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
// END - Methods for API
//
protected async processIncomingMessage(message, downloadMedia = true) {
protected shouldProcessIncomingMessage(message): boolean {
// if there is no text or media message
if (!message) return;
if (!message.Message) return;
@@ -1889,21 +1918,42 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
// Ignore key distribution messages
if (message?.Message?.senderKeyDistributionMessage) return;
}
if (downloadMedia) {
try {
message = await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
}
}
return this.toWAMessage(message);
return true;
}
protected downloadMedia(message) {
protected async processIncomingMessage(message, downloadMedia = true) {
// Filter
if (!this.shouldProcessIncomingMessage(message)) {
return null;
}
// Convert
const wamessage = this.toWAMessage(message);
// Media
if (downloadMedia) {
const media = await this.downloadMediaSafe(message);
wamessage.media = media;
}
return wamessage;
}
protected async downloadMediaSafe(message) {
try {
return await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
return null;
}
}
protected async downloadMedia(message) {
const processor = new GOWSEngineMediaProcessor(this);
return this.mediaManager.processMedia(processor, message, this.name);
const media = await this.mediaManager.processMedia(
processor,
message,
this.name,
);
return media;
}
protected toWAMessage(message): WAMessage {
@@ -1931,7 +1981,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
participant: toCusFormat(fromToParticipant.participant),
// Media
hasMedia: Boolean(mediaContent),
media: message.media || null,
media: null,
mediaUrl: message.media?.url,
// @ts-ignore
ack: ack,
+57 -18
View File
@@ -148,6 +148,7 @@ import {
LabelID,
} from '@waha/structures/labels.dto';
import { LidToPhoneNumber } from '@waha/structures/lids.dto';
import { WAMedia } from '@waha/structures/media.dto';
import { ReplyToMessage } from '@waha/structures/message.dto';
import { PaginationParams } from '@waha/structures/pagination.dto';
import {
@@ -384,6 +385,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.store = new NowebPersistentStore(
this.loggerBuilder.child({ name: NowebPersistentStore.name }),
storage,
this.jids,
);
await this.store.init();
}
@@ -1845,6 +1847,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
const messagesUpsert$ = fromEvent(this.sock.ev, 'messages.upsert').pipe(
map((event: BaileysEventMap['messages.upsert']) => event.messages),
mergeAll(),
filter((msg) => this.jids.include(msg.key.remoteJid)),
share(),
);
let [messagesFromMe$, messagesFromOthers$] = partition(
@@ -1855,6 +1858,9 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
mergeMap((msg) => this.processIncomingMessage(msg, true)),
share(), // share it so we don't process twice in message.any
);
messagesFromMe$ = messagesFromMe$.pipe(
filter((msg) => this.shouldProcessIncomingMessage(msg)),
);
messagesFromOthers$ = messagesFromOthers$.pipe(
mergeMap((msg) => this.processIncomingMessage(msg, true)),
share(), // share it so we don't process twice in message.any
@@ -1871,7 +1877,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
proto.Message.ProtocolMessage.Type.REVOKE,
),
mergeMap(async (message): Promise<WAMessageRevokedBody> => {
const afterMessage = await this.toWAMessage(message);
const afterMessage = this.toWAMessage(message);
// Extract the revoked message ID from protocolMessage.key
const revokedMessageId = message.message.protocolMessage.key?.id;
return {
@@ -1895,7 +1901,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
message.message?.protocolMessage?.editedMessage !== undefined,
),
mergeMap(async (message): Promise<WAMessageEditedBody> => {
const waMessage = await this.toWAMessage(message);
const waMessage = this.toWAMessage(message);
// Extract the body from editedMessage using extractBody function
const body =
extractBody(message.message.protocolMessage.editedMessage) || '';
@@ -1929,6 +1935,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
).pipe(
// @ts-ignore
mergeAll(),
filter((update) => this.jids.include(update.key.remoteJid)),
share(),
);
const messageAckDirect$ = messageUpdates$.pipe(
@@ -1940,6 +1947,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
fromEvent(this.sock.ev, 'message-receipt.update').pipe(
// @ts-ignore
mergeAll(),
filter((update) => this.jids.include(update.key.remoteJid)),
share(),
);
@@ -2007,6 +2015,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.events2.get(WAHAEvents.PRESENCE_UPDATE).switch(
fromEvent(this.sock.ev, 'presence.update').pipe(
filter((presence: any) => this.jids.include(presence.id)),
map((data: any) => this.toWahaPresences(data.id, data.presences)),
share(),
),
@@ -2037,7 +2046,13 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
//
// @ts-ignore
const calls$: Observable<WACallEvent[]> = fromEvent(this.sock.ev, 'call');
const call$ = calls$.pipe(mergeMap(identity), share());
const call$ = calls$.pipe(
mergeMap(identity),
filter((call: WACallEvent) =>
this.jids.include(call.groupJid || call.chatId),
),
share(),
);
this.events2.get(WAHAEvents.CALL_RECEIVED).switch(
call$.pipe(
filter((call: WACallEvent) => call.status === 'offer'),
@@ -2170,7 +2185,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return reaction;
}
protected async processIncomingMessage(message, downloadMedia = true) {
shouldProcessIncomingMessage(message): boolean {
// if there is no text or media message
if (!message) return;
if (!message.message) return;
@@ -2204,27 +2219,41 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
// Ignore key distribution messages
if (message?.message?.senderKeyDistributionMessage) return;
}
return true;
}
if (downloadMedia) {
try {
message = await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
}
protected async processIncomingMessage(
message,
downloadMedia: boolean,
): Promise<WAMessage | null> {
// Filter
if (!this.shouldProcessIncomingMessage(message)) {
return null;
}
// Convert
const wamessage = this.toWAMessageSafe(message);
if (!wamessage) {
return null;
}
// Media
if (downloadMedia) {
const media = await this.downloadMediaSafe(message);
wamessage.media = media;
}
return wamessage;
}
protected toWAMessageSafe(message): WAMessage | null {
try {
return await this.toWAMessage(message);
return this.toWAMessage(message);
} catch (error) {
this.logger.error('Failed to process incoming message');
this.logger.error(error);
console.trace(error);
return null;
}
}
protected toWAMessage(message): Promise<WAMessage> {
protected toWAMessage(message): WAMessage {
const fromToParticipant = getFromToParticipant(message.key);
const id = buildMessageId(message.key);
const body = extractBody(message.message);
@@ -2232,7 +2261,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
const ack = message.ack || StatusToAck(message.status);
const mediaContent = extractMediaContent(message.message);
const source = this.getMessageSource(message.key.id);
return Promise.resolve({
return {
id: id,
timestamp: ensureNumber(message.messageTimestamp),
from: toCusFormat(fromToParticipant.from),
@@ -2243,7 +2272,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
participant: toCusFormat(fromToParticipant.participant),
// Media
hasMedia: Boolean(mediaContent),
media: message.media || null,
media: null,
mediaUrl: message.media?.url,
// @ts-ignore
ack: ack,
@@ -2253,7 +2282,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
vCards: message.vCards,
replyTo: replyTo,
_data: message,
});
};
}
protected extractReplyTo(message): ReplyToMessage | null {
@@ -2445,7 +2474,17 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return { id: chatId, presences: presences };
}
protected downloadMedia(message) {
protected async downloadMediaSafe(message): Promise<WAMedia | null> {
try {
return await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
}
return null;
}
protected async downloadMedia(message): Promise<WAMedia | null> {
const processor = new NOWEBEngineMediaProcessor(this, this.loggerBuilder);
return this.mediaManager.processMedia(processor, message, this.name);
}
@@ -14,6 +14,7 @@ import makeWASocket, {
updateMessageWithReceipt,
WAMessage,
} from '@adiwajshing/baileys';
import { WACallEvent } from '@adiwajshing/baileys/lib/Types/Call';
import { GroupMetadata } from '@adiwajshing/baileys/lib/Types/GroupMetadata';
import { Label } from '@adiwajshing/baileys/lib/Types/Label';
import {
@@ -24,6 +25,7 @@ import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
import { IGroupRepository } from '@waha/core/engines/noweb/store/IGroupRepository';
import { ILabelAssociationRepository } from '@waha/core/engines/noweb/store/ILabelAssociationsRepository';
import { ILabelsRepository } from '@waha/core/engines/noweb/store/ILabelsRepository';
import { JidFilter } from '@waha/core/utils/jids';
import {
GetChatMessagesFilter,
OverviewFilter,
@@ -39,6 +41,7 @@ import { waitUntil } from '@waha/utils/promiseTimeout';
import * as lodash from 'lodash';
import { toNumber } from 'lodash';
import { Logger } from 'pino';
import { filter } from 'rxjs';
import { IChatRepository } from './IChatRepository';
import { IContactRepository } from './IContactRepository';
@@ -82,6 +85,7 @@ export class NowebPersistentStore implements INowebStore {
constructor(
private logger: Logger,
public storage: INowebStorage,
private jids: JidFilter,
) {
this.socket = null;
this.chatRepo = storage.getChatRepository();
@@ -247,6 +251,7 @@ export class NowebPersistentStore implements INowebStore {
private async syncMessagesHistory(messages) {
const realMessages = messages.filter(isRealMessage);
messages = messages.filter((msg) => this.jids.include(msg.key.remoteJid));
await this.messagesRepo.upsert(realMessages);
this.logger.info(
`history sync - '${messages.length}' got messages, '${realMessages.length}' real messages`,
@@ -254,11 +259,13 @@ export class NowebPersistentStore implements INowebStore {
}
private async onMessagesUpsert(update) {
const { messages, type } = update;
const type = update.type;
if (type !== 'notify' && type !== 'append') {
this.logger.debug(`unexpected type for messages.upsert: '${type}'`);
return;
}
let messages = update.messages;
messages = messages.filter((msg) => this.jids.include(msg.key.remoteJid));
const realMessages = messages.filter(isRealMessage);
await this.messagesRepo.upsert(realMessages);
this.logger.debug(
@@ -270,6 +277,9 @@ export class NowebPersistentStore implements INowebStore {
for (const update of updates) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const jid = jidNormalizedUser(update.key.remoteJid!);
if (!this.jids.include(jid)) {
continue;
}
if (!update.key.id) {
continue;
}
@@ -333,12 +343,16 @@ export class NowebPersistentStore implements INowebStore {
delete chat['messages'];
chat.conversationTimestamp = toNumber(chat.conversationTimestamp) || null;
}
chats = chats.filter((chat) => this.jids.include(chat.id));
await this.chatRepo.upsertMany(chats);
this.logger.info(`store sync - '${chats.length}' synced chats`);
}
private async onGroupUpsert(groups: GroupMetadata[]) {
for (const group of groups) {
if (!this.jids.include(group.id)) {
continue;
}
await this.groupRepo.save(group);
}
this.logger.info(`store sync - '${groups.length}' synced groups`);
@@ -346,6 +360,9 @@ export class NowebPersistentStore implements INowebStore {
private async onGroupUpdate(groups: Partial<GroupMetadata>[]) {
for (const update of groups) {
if (!this.jids.include(update.id)) {
continue;
}
let group = await this.groupRepo.getById(update.id);
group = Object.assign(group || {}, update) as GroupMetadata;
await this.groupRepo.save(group);
@@ -356,6 +373,9 @@ export class NowebPersistentStore implements INowebStore {
private async onGroupParticipantsUpdate(data) {
const id: string = data.id;
if (!this.jids.include(id)) {
return;
}
const participants: string[] = data.participants;
const action: ParticipantAction = data.action;
@@ -419,6 +439,9 @@ export class NowebPersistentStore implements INowebStore {
private async onChatUpdate(updates: ChatUpdate[]) {
for (const update of updates) {
if (!this.jids.include(update.id)) {
continue;
}
const chat = (await this.chatRepo.getById(update.id)) || ({} as Chat);
Object.assign(chat, update);
chat.conversationTimestamp = toNumber(chat.conversationTimestamp) || null;
@@ -447,6 +470,9 @@ export class NowebPersistentStore implements INowebStore {
const ids = contacts.map((c) => c.id);
const contactById = await this.contactRepo.getEntitiesByIds(ids);
for (const update of contacts) {
if (!this.jids.include(update.id)) {
continue;
}
const contact = contactById.get(update.id) || {};
// remove undefined from data
Object.keys(update).forEach(
@@ -460,6 +486,9 @@ export class NowebPersistentStore implements INowebStore {
private async onContactUpdate(updates: Partial<Contact>[]) {
for (const update of updates) {
if (!this.jids.include(update.id)) {
continue;
}
let contact = await this.contactRepo.getById(update.id);
if (!contact) {
@@ -493,6 +522,9 @@ export class NowebPersistentStore implements INowebStore {
private async onMessageReaction(reactions) {
for (const { key, reaction } of reactions) {
if (!this.jids.include(key.remoteJid)) {
continue;
}
const msg = await this.messagesRepo.getByJidById(key.remoteJid, key.id);
if (!msg) {
this.logger.warn(
@@ -509,6 +541,9 @@ export class NowebPersistentStore implements INowebStore {
private async onMessageReceiptUpdate(updates) {
for (const { key, receipt } of updates) {
if (!this.jids.include(key.remoteJid)) {
continue;
}
const msg = await this.messagesRepo.getByJidById(key.remoteJid, key.id);
if (!msg) {
this.logger.warn(
@@ -544,6 +579,9 @@ export class NowebPersistentStore implements INowebStore {
}
private async onPresenceUpdate({ id, presences: update }) {
if (!this.jids.include(id)) {
return;
}
this.presences[id] = this.presences[id] || {};
Object.assign(this.presences[id], update);
}
@@ -446,7 +446,7 @@ export default (config: BaileysInMemoryStoreConfig) => {
) => {
const list = assertMessageList(jid);
const mode = !cursor || 'before' in cursor ? 'before' : 'after';
const cursorKey = !!cursor
const cursorKey = cursor
? 'before' in cursor
? cursor.before
: cursor.after
+30 -1
View File
@@ -30,7 +30,10 @@ export class WebjsClientCore extends Client {
public events = new EventEmitter();
private wpage: WPage = null;
constructor(options) {
constructor(
options,
protected tags: boolean,
) {
super(options);
// Wait until it's READY and inject more utils
this.on(Events.READY, async () => {
@@ -86,6 +89,32 @@ export class WebjsClientCore extends Client {
return;
},
);
if (this.tags) {
await this.attachTagsEvents();
}
}
async attachTagsEvents() {
await this.pupPage.evaluate(() => {
// @ts-ignore
if (window.decodeStanzaBack) {
return;
}
const tags = ['receipt', 'presence', 'chatstate'];
// @ts-ignore
window.decodeStanzaBack = window.Store.SocketWap.decodeStanza;
// @ts-ignore
window.Store.SocketWap.decodeStanza = async (...args) => {
// @ts-ignore
const result = await window.decodeStanzaBack(...args);
if (tags.includes(result?.tag)) {
// @ts-ignore
setTimeout(() => window.onTag(result), 0);
}
return result;
};
});
}
async destroy() {
+48 -13
View File
@@ -103,6 +103,7 @@ import {
} from '@waha/structures/groups.dto';
import { Label, LabelDTO, LabelID } from '@waha/structures/labels.dto';
import { LidToPhoneNumber } from '@waha/structures/lids.dto';
import { WAMedia } from '@waha/structures/media.dto';
import { ReplyToMessage } from '@waha/structures/message.dto';
import { PaginationParams, SortOrder } from '@waha/structures/pagination.dto';
import {
@@ -235,7 +236,14 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
rmMaxRetries: undefined,
});
this.addProxyConfig(clientOptions);
return new WebjsClientCore(clientOptions);
return new WebjsClientCore(clientOptions, this.getWebjsTagsFlag());
}
protected getWebjsTagsFlag() {
// Emit 'tag:*' events only when explicitly enabled in session config.
// This flag is required for presence.update and message.ack events.
// Disabled by default for performance and stability reasons.
return !!this.sessionConfig?.webjs?.tagsEventsOn;
}
private restartClient() {
@@ -783,7 +791,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
chat.id._serialized,
false,
);
const lastMessage = !!chat.lastMessage
const lastMessage = chat.lastMessage
? this.toWAMessage(chat.lastMessage)
: null;
return {
@@ -1439,6 +1447,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
//
const messageReceived$ = fromEvent(this.whatsapp, Events.MESSAGE_RECEIVED);
const messagesFromOthers$ = messageReceived$.pipe(
filter((msg: Message) => this.jids.include(msg?.id?.remote)),
mergeMap((msg: any) => this.processIncomingMessage(msg, true)),
share(),
);
@@ -1446,6 +1455,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
const messageCreate$ = fromEvent(this.whatsapp, Events.MESSAGE_CREATE);
const messagesFromAll$ = messageCreate$.pipe(
filter((msg: Message) => this.jids.include(msg?.id?.remote)),
mergeMap((msg: any) => this.processIncomingMessage(msg, true)),
share(),
);
@@ -1456,6 +1466,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
Events.MESSAGE_CIPHERTEXT,
);
const messagesWaiting$ = messageCiphertext$.pipe(
filter((msg: Message) => this.jids.include(msg?.id?.remote)),
mergeMap((msg: any) => this.processIncomingMessage(msg, false)),
share(),
);
@@ -1469,6 +1480,9 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
},
);
const messagesRevoked$ = messageRevoked$.pipe(
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
@@ -1487,6 +1501,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
const messageReaction$ = fromEvent(this.whatsapp, 'message_reaction');
const messagesReaction$ = messageReaction$.pipe(
filter((reaction: Reaction) => this.jids.include(reaction?.id?.remote)),
map(this.processMessageReaction.bind(this)),
filter(Boolean),
);
@@ -1500,6 +1515,7 @@ 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 {
@@ -1523,6 +1539,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
map((event) => event.message),
map<any, WAMessage>(this.toWAMessage.bind(this)),
filter((ack) => !isJidGroup(ack.to) && !isJidStatusBroadcast(ack.to)),
filter((ack) => this.jids.include(ack.to)),
);
const tagReceiptNode$ = fromEvent(this.whatsapp, Events.TAG_RECEIPT);
const messageAckGroups$ = tagReceiptNode$.pipe(
@@ -1532,6 +1549,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
filter(Boolean),
mergeMap(this.TagReceiptToMessageAck.bind(this)),
filter((ack) => isJidGroup(ack.to) || isJidStatusBroadcast(ack.to)),
filter((ack) => this.jids.include(ack.to)),
);
const messageAckAll$ = merge(messagesAckDM$, messageAckGroups$);
@@ -1552,11 +1570,13 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
const presences$ = tagPresenceNode$.pipe(
map(TagPresenceToPresence),
filter(Boolean),
filter((presence: any) => this.jids.include(presence.id)),
);
const tagChatstateNode$ = fromEvent(this.whatsapp, 'tag:chatstate');
const chatstatePresences$ = tagChatstateNode$.pipe(
map(TagChatstateToPresence),
filter(Boolean),
filter((presence: any) => this.jids.include(presence.id)),
);
const presenceUpdate$ = merge(presences$, chatstatePresences$);
this.events2.get(WAHAEvents.PRESENCE_UPDATE).switch(presenceUpdate$);
@@ -1625,6 +1645,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
},
);
const chatsArchived$ = chatArchived$.pipe(
filter((event: any) => this.jids.include(event?.chat?.id?._serialized)),
map((event) => {
return {
id: event.chat.id._serialized,
@@ -1640,6 +1661,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
//
const call$ = fromEvent(this.whatsapp, 'call');
const calls$ = call$.pipe(
filter((call: Call) => this.jids.include((call as any)?.from)),
map((call: Call) => {
return {
id: call.id,
@@ -1657,15 +1679,14 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
message: Message,
downloadMedia = true,
) {
// Convert
const wamessage = this.toWAMessage(message);
// Media
if (downloadMedia) {
try {
message = await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
}
const media = await this.downloadMediaSafe(message);
wamessage.media = media;
}
return this.toWAMessage(message);
return wamessage;
}
private processMessageReaction(reaction: Reaction): WAMessageReaction {
@@ -1737,8 +1758,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
// Media
// @ts-ignore
hasMedia: Boolean(message.hasMedia),
// @ts-ignore
media: message.media || null,
media: null,
// @ts-ignore
mediaUrl: message.media?.url,
// @ts-ignore
@@ -1781,9 +1801,24 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return contact;
}
protected downloadMedia(message: Message) {
protected async downloadMediaSafe(message): Promise<WAMedia | null> {
try {
return await this.downloadMedia(message);
} catch (e) {
this.logger.error('Failed when tried to download media for a message');
this.logger.error(e, e.stack);
}
return null;
}
protected async downloadMedia(message: Message) {
const processor = new WEBJSEngineMediaProcessor();
return this.mediaManager.processMedia(processor, message, this.name);
const media = await this.mediaManager.processMedia(
processor,
message,
this.name,
);
return media;
}
protected getMessageOptions(request: any): any {
+1
View File
@@ -200,6 +200,7 @@ export class SessionManagerCore extends SessionManager implements OnModuleInit {
sessionStore: this.store,
proxyConfig: proxyConfig,
sessionConfig: this.sessionConfig,
ignore: this.ignoreChatsConfig(this.sessionConfig),
};
if (this.EngineClass === WhatsappSessionWebJSCore) {
sessionConfig.engineConfig = this.webjsEngineConfigService.getConfig();
+2 -1
View File
@@ -1,4 +1,5 @@
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
import { WAMedia } from '@waha/structures/media.dto';
/**
* General interface for MediaManager - one that handles the logic
@@ -9,7 +10,7 @@ interface IMediaManager {
processor: IMediaEngineProcessor<Message>,
message: Message,
session: string,
): Promise<Message>;
): Promise<WAMedia | null>;
close(): void;
}
+2 -4
View File
@@ -102,7 +102,7 @@ export class MediaManager implements IMediaManager {
processor: IMediaEngineProcessor<Message>,
message: Message,
session: string,
): Promise<Message> {
): Promise<WAMedia | null> {
let messageId: string;
try {
messageId = processor.getMessageId(message);
@@ -134,9 +134,7 @@ export class MediaManager implements IMediaManager {
// @ts-ignore
media.error.details = `${err.stack}`;
}
// @ts-ignore
message.media = media;
return message;
return media;
}
private async fetchMedia(
+27 -2
View File
@@ -1,11 +1,15 @@
import { isJidGroup, isJidMetaIa } from '@adiwajshing/baileys';
import {
isJidGroup,
isJidMetaIa,
isJidStatusBroadcast,
} from '@adiwajshing/baileys';
import {
isJidBroadcast,
isLidUser,
} from '@adiwajshing/baileys/lib/WABinary/jid-utils';
export function isJidNewsletter(jid: string) {
return jid.endsWith('@newsletter');
return jid?.endsWith('@newsletter');
}
export function isJidCus(jid: string) {
@@ -35,3 +39,24 @@ export function toJID(chatId) {
const number = chatId.split('@')[0];
return number + '@s.whatsapp.net';
}
export interface IgnoreJidConfig {
status: boolean;
groups: boolean;
channels: boolean;
}
export class JidFilter {
constructor(public ignore: IgnoreJidConfig) {}
include(jid: string): boolean {
if (this.ignore.status && isJidStatusBroadcast(jid)) {
return false;
} else if (this.ignore.groups && isJidGroup(jid)) {
return false;
} else if (this.ignore.channels && isJidNewsletter(jid)) {
return false;
}
return true;
}
}
+58
View File
@@ -89,6 +89,42 @@ export class NowebConfig {
markOnline: boolean = true;
}
export class WebjsConfig {
@ApiProperty({
description:
"Enable emission of special 'tag:*' engine events required for presence.update and message.ack.\n" +
'WARNING: Enabling this may have performance and stability impact. Disabled by default.',
required: false,
default: false,
})
@IsBoolean()
@IsOptional()
tagsEventsOn?: boolean = false;
}
export class IgnoreConfig {
@ApiProperty({
description: 'Ignore a status@broadcast (stories) events',
})
@IsBoolean()
@IsOptional()
status?: boolean;
@ApiProperty({
description: 'Ignore groups events',
})
@IsBoolean()
@IsOptional()
groups?: boolean;
@ApiProperty({
description: 'Ignore channels events',
})
@IsBoolean()
@IsOptional()
channels?: boolean;
}
export class SessionConfig {
@ValidateNested({ each: true })
@Type(() => WebhookConfig)
@@ -125,6 +161,19 @@ export class SessionConfig {
@IsOptional()
debug?: boolean;
@ApiProperty({
example: {
status: null,
groups: null,
channels: null,
},
description: 'Ignore some events related to specific chats',
})
@ValidateNested()
@Type(() => IgnoreConfig)
@IsOptional()
ignore?: IgnoreConfig;
@ApiProperty({
example: {
store: {
@@ -137,6 +186,15 @@ export class SessionConfig {
@Type(() => NowebConfig)
@IsOptional()
noweb?: NowebConfig;
@ApiProperty({
description: 'WebJS-specific settings.',
required: false,
})
@ValidateNested()
@Type(() => WebjsConfig)
@IsOptional()
webjs?: WebjsConfig;
}
export class SessionDTO {
+1 -1
View File
@@ -30,7 +30,7 @@ export function getWAHAVersion(): WAHAVersion {
}
export const VERSION: WAHAEnvironment = {
version: '2025.8.2',
version: '2025.8.3',
engine: getEngineName(),
tier: getWAHAVersion(),
browser:
+2 -2
View File
@@ -2,11 +2,11 @@
"waha": {
"gows": {
"repo": "devlikeapro/gows",
"ref": "v1.0.12"
"ref": "v1.0.13"
},
"dashboard": {
"repo": "devlikeapro/dashboard",
"ref": "c6bf800fec183644ad820343f97e0caf8c71ed98"
"ref": "a29267de044e439535f99bff42568aec5df7b462"
}
}
}
+158 -1507
View File
File diff suppressed because it is too large. Load diff