Compare commits

...
9 Commits
Author SHA1 Message Date
devlikepro 703b0b4cde [core] Fix groups sort by
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 / NOWEB - none - amd64 - noweb (push) Waiting to run
Release / NOWEB - none - linux/arm64 - noweb-arm (push) Waiting to run
2024-12-09 11:30:39 +07:00
devlikepro d55895389a [core] 2024.12.3 2024-12-09 10:37:35 +07:00
devlikepro 56009e482b [core] Add dedicated POST /api/{session}/groups/refresh endpoint 2024-12-09 10:19:38 +07:00
devlikepro 767d1bb3e3 [core] Fix 'rate-overlimit' error for groups
fix #462
2024-12-08 18:23:39 +07:00
devlikepro 05132ac0f5 [core] Update NOWEB 1018710061 2024-12-08 18:23:39 +07:00
devlikepro fb372f8c28 [core] Set WHATSAPP_DEFAULT_ENGINE at build time
fix #414
2024-12-08 13:52:43 +07:00
devlikepro a2dc863b7a [core] 12.2
Release / amd64 - chrome - chrome (push) Waiting to run
Release / amd64 - chromium - latest (push) Waiting to run
Release / linux/arm64 - chromium - arm (push) Waiting to run
Release / amd64 - none - noweb (push) Waiting to run
Release / linux/arm64 - none - noweb-arm (push) Waiting to run
2024-12-07 00:15:49 +07:00
devlikepro 15671c6781 [core] NOWEB - potential fix for #671 2024-12-07 00:15:34 +07:00
devlikepro 6296115adb [core] Cache keys between restart 2024-12-07 00:15:34 +07:00
18 changed files with 335 additions and 27 deletions

No files matched your search

+10 -1
View File
@@ -8,7 +8,9 @@ on:
jobs:
docker-build:
runs-on: ${{ matrix.runner }}
name: ${{ matrix.platform }} - ${{ matrix.browser }} - ${{ matrix.tag }}
name:
${{ matrix.engine }} - ${{ matrix.browser }} - ${{ matrix.platform }} -
${{ matrix.tag }}
strategy:
matrix:
include:
@@ -17,6 +19,7 @@ jobs:
tag: 'latest'
platform: 'amd64'
browser: 'chromium'
engine: 'WEBJS'
goss: 'goss-linux-amd64'
# Chromium - ARM
@@ -24,6 +27,7 @@ jobs:
tag: 'arm'
platform: 'linux/arm64'
browser: 'chromium'
engine: 'WEBJS'
goss: 'goss-linux-arm'
# Chrome - x86
@@ -31,6 +35,7 @@ jobs:
tag: 'chrome'
platform: 'amd64'
browser: 'chrome'
engine: 'WEBJS'
goss: 'goss-linux-amd64'
# Chrome - ARM (Chrome is not available for ARM)
@@ -45,6 +50,7 @@ jobs:
tag: 'noweb'
platform: 'amd64'
browser: 'none'
engine: 'NOWEB'
goss: 'goss-linux-amd64'
# No browser - ARM
@@ -52,6 +58,7 @@ jobs:
tag: 'noweb-arm'
platform: 'linux/arm64'
browser: 'none'
engine: 'NOWEB'
goss: 'goss-linux-arm'
steps:
@@ -85,6 +92,7 @@ jobs:
platforms: ${{ matrix.platform }}
build-args: |
USE_BROWSER=${{ matrix.browser }}
WHATSAPP_DEFAULT_ENGINE=${{ matrix.engine }}
push: false
load: true
tags: ${{ steps.meta.outputs.tags }}
@@ -116,6 +124,7 @@ jobs:
platforms: ${{ matrix.platform }}
build-args: |
USE_BROWSER=${{ matrix.browser }}
WHATSAPP_DEFAULT_ENGINE=${{ matrix.engine }}
push: ${{ github.ref_type == 'tag' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+4
View File
@@ -44,6 +44,7 @@ ENV PUPPETEER_SKIP_DOWNLOAD=True
# https://github.com/devlikeapro/waha/issues/347
ENV NODE_OPTIONS="--max-old-space-size=16384"
ARG USE_BROWSER=chromium
ARG WHATSAPP_DEFAULT_ENGINE
RUN echo "USE_BROWSER=$USE_BROWSER"
@@ -99,6 +100,9 @@ RUN if [ "$USE_BROWSER" = "chrome" ]; then \
&& rm -rf /var/lib/apt/lists/*; \
fi
# Set the ENV for NOWEB docker image
ENV WHATSAPP_DEFAULT_ENGINE=$WHATSAPP_DEFAULT_ENGINE
# Attach sources, install packages
WORKDIR /app
COPY package.json ./
+1 -1
View File
@@ -5,7 +5,7 @@ build-chrome:
docker build . -t devlikeapro/waha-plus:chrome --build-arg USE_BROWSER=chrome
build-noweb:
docker build . -t devlikeapro/waha:noweb --build-arg USE_BROWSER=none
docker build . -t devlikeapro/waha:noweb --build-arg USE_BROWSER=none --build-arg WHATSAPP_DEFAULT_ENGINE=NOWEB
build-all: build build-chrome build-noweb
+18 -2
View File
@@ -6,6 +6,9 @@ import {
Param,
Post,
Put,
Query,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { GroupIdApiParam } from '@waha/nestjs/params/ChatIdApiParam';
@@ -19,6 +22,7 @@ import { WhatsappSession } from '../core/abc/session.abc';
import {
CreateGroupRequest,
DescriptionRequest,
GroupsPaginationParams,
ParticipantsRequest,
SettingsSecurityChangeInfo,
SubjectRequest,
@@ -43,8 +47,20 @@ export class GroupsController {
@Get('')
@SessionApiParam
@ApiOperation({ summary: 'Get all groups.' })
getGroups(@WorkingSessionParam session: WhatsappSession) {
return session.getGroups();
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
getGroups(
@WorkingSessionParam session: WhatsappSession,
@Query() pagination: GroupsPaginationParams,
) {
return session.getGroups(pagination);
}
@Post('refresh')
@SessionApiParam
@ApiOperation({ summary: 'Refresh groups from the server.' })
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
async refreshGroups(@WorkingSessionParam session: WhatsappSession) {
return { success: await session.refreshGroups() };
}
@Get(':id')
+6 -1
View File
@@ -61,6 +61,7 @@ import {
} from '../../structures/enums.dto';
import {
CreateGroupRequest,
GroupsPaginationParams,
ParticipantsRequest,
SettingsSecurityChangeInfo,
} from '../../structures/groups.dto';
@@ -522,7 +523,11 @@ export abstract class WhatsappSession {
throw new NotImplementedByEngineError();
}
public getGroups() {
public getGroups(pagination: PaginationParams) {
throw new NotImplementedByEngineError();
}
public refreshGroups(): Promise<boolean> {
throw new NotImplementedByEngineError();
}
+19 -9
View File
@@ -270,11 +270,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return {
agent: agent,
fetchAgent: agent,
auth: {
creds: state.creds,
/** caching makes the store faster to send/recv messages */
keys: makeCacheableSignalKeyStore(state.keys, this.engineLogger),
},
auth: state,
printQRInTerminal: false,
browser: browser,
logger: this.engineLogger,
@@ -291,10 +287,16 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
async makeSocket(): Promise<any> {
if (!this.authNOWEBStore) {
this.authNOWEBStore = await this.authFactory.buildAuth(
const store = await this.authFactory.buildAuth(
this.sessionStore,
this.name,
);
/** caching makes the store faster to send/recv messages */
store.state.keys = makeCacheableSignalKeyStore(
store.state.keys,
this.engineLogger,
);
this.authNOWEBStore = store;
}
const { state, saveCreds } = this.authNOWEBStore;
const agent = this.makeAgent();
@@ -1082,12 +1084,20 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return this.sock.groupCreate(request.name, participants);
}
public async getGroups() {
return await this.sock.groupFetchAllParticipating();
public async getGroups(pagination: PaginationParams) {
const groups = await this.store.getGroups(pagination);
// return {id: group} mapping for backward compatability
return lodash.keyBy(groups, 'id');
}
public async refreshGroups(): Promise<boolean> {
this.store.resetGroupsCache();
await this.store.getGroups({});
return true;
}
public async getGroup(id) {
const groups = await this.sock.groupFetchAllParticipating();
const groups = await this.getGroups({});
return groups[id];
}
@@ -0,0 +1,14 @@
import { GroupMetadata } from '@adiwajshing/baileys';
import { PaginationParams } from '@waha/structures/pagination.dto';
export interface IGroupRepository {
getAll(pagination?: PaginationParams): Promise<GroupMetadata[]>;
getById(id: string): Promise<GroupMetadata | null>;
deleteAll(): Promise<void>;
deleteById(id: string): Promise<void>;
save(group: GroupMetadata): Promise<void>;
}
@@ -1,5 +1,6 @@
import { WAMessage } from '@adiwajshing/baileys';
import { LabelAssociation } from '@adiwajshing/baileys/lib/Types/LabelAssociation';
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';
@@ -16,6 +17,8 @@ export abstract class INowebStorage {
abstract getChatRepository(): IChatRepository;
abstract getGroupRepository(): IGroupRepository;
abstract getMessagesRepository(): IMessagesRepository;
abstract getLabelsRepository(): ILabelsRepository;
@@ -4,6 +4,7 @@ import {
Contact,
proto,
} from '@adiwajshing/baileys';
import { GroupMetadata } from '@adiwajshing/baileys/lib/Types/GroupMetadata';
import { Label } from '@adiwajshing/baileys/lib/Types/Label';
import { GetChatMessagesFilter } from '@waha/structures/chats.dto';
import { PaginationParams } from '@waha/structures/pagination.dto';
@@ -40,4 +41,8 @@ export interface INowebStore {
getChatsByLabelId(labelId: string): Promise<Chat[]>;
getChatLabels(chatId: string): Promise<Label[]>;
getGroups(pagination: PaginationParams): Promise<GroupMetadata[]>;
resetGroupsCache(): void;
}
@@ -1,8 +1,15 @@
import { Chat, Contact, makeInMemoryStore, proto } from '@adiwajshing/baileys';
import makeWASocket, {
Chat,
Contact,
GroupMetadata,
makeInMemoryStore,
proto,
} from '@adiwajshing/baileys';
import { Label } from '@adiwajshing/baileys/lib/Types/Label';
import { BadRequestException } from '@nestjs/common';
import { GetChatMessagesFilter } from '@waha/structures/chats.dto';
import { PaginationParams } from '@waha/structures/pagination.dto';
import { PaginatorInMemory } from '@waha/utils/Paginator';
import { INowebStore } from './INowebStore';
@@ -10,6 +17,8 @@ import { INowebStore } from './INowebStore';
const logger = require('pino')();
export class NowebInMemoryStore implements INowebStore {
private socket: ReturnType<typeof makeWASocket>;
private store: ReturnType<typeof makeInMemoryStore>;
errorMessage =
'Enable NOWEB store "config.noweb.store.enabled=True" and "config.noweb.store.full_sync=True" when starting a new session. ' +
@@ -33,6 +42,7 @@ export class NowebInMemoryStore implements INowebStore {
bind(ev: any, socket: any) {
this.store.bind(ev);
this.socket = socket;
}
loadMessage(jid: string, id: string): Promise<proto.IWebMessageInfo> {
@@ -78,4 +88,15 @@ export class NowebInMemoryStore implements INowebStore {
getChatLabels(chatId: string): Promise<Label[]> {
throw new BadRequestException(this.errorMessage);
}
async getGroups(pagination: PaginationParams): Promise<GroupMetadata[]> {
const response = await this.socket?.groupFetchAllParticipating();
const groups = Object.values(response);
const paginator = new PaginatorInMemory(pagination);
return paginator.apply(groups);
}
resetGroupsCache() {
return;
}
}
@@ -1,27 +1,34 @@
import {
import makeWASocket, {
areJidsSameUser,
BaileysEventEmitter,
Chat,
ChatUpdate,
Contact,
GroupParticipant,
isRealMessage,
jidNormalizedUser,
ParticipantAction,
proto,
updateMessageWithReaction,
updateMessageWithReceipt,
} from '@adiwajshing/baileys';
import { GroupMetadata } from '@adiwajshing/baileys/lib/Types/GroupMetadata';
import { Label } from '@adiwajshing/baileys/lib/Types/Label';
import {
LabelAssociation,
LabelAssociationType,
} from '@adiwajshing/baileys/lib/Types/LabelAssociation';
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 { GetChatMessagesFilter } from '@waha/structures/chats.dto';
import { PaginationParams, SortOrder } from '@waha/structures/pagination.dto';
import { DefaultMap } from '@waha/utils/DefaultMap';
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
import * as lodash from 'lodash';
import { toNumber } from 'lodash';
import { Logger } from 'pino';
import { toJID } from '../session.noweb.core';
import { IChatRepository } from './IChatRepository';
import { IContactRepository } from './IContactRepository';
import { IMessagesRepository } from './IMessagesRepository';
@@ -31,15 +38,27 @@ import { INowebStore } from './INowebStore';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const AsyncLock = require('async-lock');
type ms = number;
const HOUR: ms = 60 * 60 * 1000;
export class NowebPersistentStore implements INowebStore {
private socket: any;
private socket: ReturnType<typeof makeWASocket>;
private chatRepo: IChatRepository;
private groupRepo: IGroupRepository;
private contactRepo: IContactRepository;
private messagesRepo: IMessagesRepository;
private labelsRepo: ILabelsRepository;
private labelAssociationsRepo: ILabelAssociationRepository;
public presences: any;
private lock: any;
private groupsFetchLock: any = new AsyncLock({
maxPending: Infinity,
maxExecutionTime: 60_000,
});
private lastTimeGroupUpdate: Date = new Date(0);
private lastTimeGroupFetch: Date = new Date(0);
private GROUP_METADATA_CACHE_TIME = 24 * HOUR;
constructor(
private logger: Logger,
@@ -47,6 +66,7 @@ export class NowebPersistentStore implements INowebStore {
) {
this.socket = null;
this.chatRepo = storage.getChatRepository();
this.groupRepo = storage.getGroupRepository();
this.contactRepo = storage.getContactsRepository();
this.messagesRepo = storage.getMessagesRepository();
this.labelsRepo = storage.getLabelsRepository();
@@ -88,6 +108,19 @@ export class NowebPersistentStore implements INowebStore {
ev.on('chats.delete', (data) =>
this.withLock('chats', () => this.onChatDelete(data)),
);
// Groups
ev.on('groups.upsert', (data) =>
this.withLock('groups', () => this.onGroupUpsert(data)),
);
ev.on('groups.update', (data) =>
this.withLock('groups', () => this.onGroupUpdate(data)),
);
ev.on('group-participants.update', (data) =>
this.withLock(`group-${data.id}`, () =>
this.onGroupParticipantsUpdate(data),
),
);
// Contacts
ev.on('contacts.upsert', (data) =>
this.withLock('contacts', () => this.onContactsUpsert(data)),
@@ -195,7 +228,84 @@ export class NowebPersistentStore implements INowebStore {
chat.conversationTimestamp = toNumber(chat.conversationTimestamp);
await this.chatRepo.save(chat);
}
this.logger.info(`history sync - '${chats.length}' synced chats`);
this.logger.info(`store sync - '${chats.length}' synced chats`);
}
private async onGroupUpsert(groups: GroupMetadata[]) {
for (const group of groups) {
await this.groupRepo.save(group);
}
this.logger.info(`store sync - '${groups.length}' synced groups`);
}
private async onGroupUpdate(groups: Partial<GroupMetadata>[]) {
for (const update of groups) {
let group = await this.groupRepo.getById(update.id);
group = Object.assign(group || {}, update) as GroupMetadata;
await this.groupRepo.save(group);
}
this.logger.info(`store sync - '${groups.length}' updated groups`);
this.lastTimeGroupUpdate = new Date();
}
private async onGroupParticipantsUpdate(data) {
const id: string = data.id;
const participants: string[] = data.participants;
const action: ParticipantAction = data.action;
if (action == 'remove') {
// Remove the group if the current user is removed
const myJid = this.socket?.authState?.creds?.me?.id;
const participantsIncludesMe = lodash.find(participants, (p) =>
areJidsSameUser(p, myJid),
);
if (participantsIncludesMe) {
await this.groupRepo.deleteById(id);
return;
}
}
let group = await this.groupRepo.getById(id);
if (!group) {
group = { id: id, participants: [] } as GroupMetadata;
}
const participantsById = new DefaultMap<string, GroupParticipant>((key) => {
return { id: key, admin: null } as GroupParticipant;
});
for (const participant of group.participants) {
participantsById.set(participant.id, participant);
}
for (const participant of participants) {
this.participantUpdate(participantsById, participant, action);
}
group.participants = Array.from(participantsById.values());
await this.groupRepo.save(group);
}
private participantUpdate(
participantsById: DefaultMap<string, GroupParticipant>,
participant: string,
action: ParticipantAction,
) {
switch (action) {
case 'add':
// if there's no participant - add it (by id)
participantsById.get(participant);
break;
case 'remove':
// remove the participant (by id)
participantsById.delete(participant);
break;
case 'promote':
// set admin: admin
participantsById.get(participant).admin = 'admin';
break;
case 'demote':
participantsById.get(participant).admin = null;
break;
}
}
private async onChatUpdate(updates: ChatUpdate[]) {
@@ -344,6 +454,41 @@ export class NowebPersistentStore implements INowebStore {
return this.chatRepo.getAllWithMessages(pagination);
}
private shouldFetchGroup(): boolean {
const timePassed = new Date().getTime() - this.lastTimeGroupFetch.getTime();
return timePassed > this.GROUP_METADATA_CACHE_TIME;
}
private async fetchGroups() {
await this.groupsFetchLock.acquire('groups-fetch', async () => {
if (!this.shouldFetchGroup()) {
// Update has been done by another request
return;
}
const lastTimeGroupUpdate = this.lastTimeGroupUpdate;
await this.groupRepo.deleteAll();
await this.socket?.groupFetchAllParticipating();
// Wait until the groups update is done
await waitUntil(
async () => this.lastTimeGroupUpdate > lastTimeGroupUpdate,
100,
5_000,
);
this.lastTimeGroupFetch = new Date();
});
}
resetGroupsCache() {
this.lastTimeGroupFetch = new Date(0);
}
async getGroups(pagination: PaginationParams): Promise<GroupMetadata[]> {
if (this.shouldFetchGroup()) {
await this.fetchGroups();
}
return this.groupRepo.getAll(pagination);
}
getContactById(jid) {
return this.contactRepo.getById(jid);
}
+5
View File
@@ -18,6 +18,11 @@ export const NOWEB_STORE_SCHEMA = [
new Index('chats_conversationTimestamp_index', ['conversationTimestamp']),
],
),
new Schema(
'groups',
[new Field('id', 'TEXT'), new Field('data', 'TEXT')],
[new Index('groups_id_index', ['id'])],
),
new Schema(
'messages',
[
@@ -0,0 +1,16 @@
import { GroupMetadata } from '@adiwajshing/baileys/lib/Types/GroupMetadata';
import { IGroupRepository } from '@waha/core/engines/noweb/store/IGroupRepository';
import { KnexPaginator } from '@waha/utils/Paginator';
import { NOWEBSqlite3KVRepository } from './NOWEBSqlite3KVRepository';
class Paginator extends KnexPaginator {
indexes = ['id'];
}
export class Sqlite3GroupRepository
extends NOWEBSqlite3KVRepository<GroupMetadata>
implements IGroupRepository
{
protected Paginator = Paginator;
}
@@ -2,6 +2,7 @@ import { WAMessage } from '@adiwajshing/baileys';
import { LabelAssociation } from '@adiwajshing/baileys/lib/Types/LabelAssociation';
import { ILabelAssociationRepository } from '@waha/core/engines/noweb/store/ILabelAssociationsRepository';
import { ILabelsRepository } from '@waha/core/engines/noweb/store/ILabelsRepository';
import { Sqlite3GroupRepository } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3GroupRepository';
import { Sqlite3LabelAssociationsRepository } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3LabelAssociationsRepository';
import { Sqlite3LabelsRepository } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3LabelsRepository';
import { Field, Index, Schema } from '@waha/core/storage/sqlite3/Schema';
@@ -62,6 +63,14 @@ export class Sqlite3Storage extends INowebStorage {
'CREATE INDEX IF NOT EXISTS chats_conversationTimestamp_index ON chats (conversationTimestamp)',
);
// Groups
this.db.exec(
'CREATE TABLE IF NOT EXISTS groups (id TEXT PRIMARY KEY, data TEXT)',
);
this.db.exec(
'CREATE UNIQUE INDEX IF NOT EXISTS groups_id_index ON groups (id)',
);
// Messages
this.db.exec(
'CREATE TABLE IF NOT EXISTS messages (jid TEXT, id TEXT, messageTimestamp INTEGER, data TEXT)',
@@ -119,6 +128,10 @@ export class Sqlite3Storage extends INowebStorage {
return new Sqlite3ChatRepository(this.db, this.getSchema('chats'));
}
getGroupRepository() {
return new Sqlite3GroupRepository(this.db, this.getSchema('groups'));
}
getLabelsRepository(): ILabelsRepository {
return new Sqlite3LabelsRepository(this.db, this.getSchema('labels'));
}
+21 -4
View File
@@ -55,6 +55,7 @@ import {
} from '@waha/structures/enums.dto';
import {
CreateGroupRequest,
GroupSortField,
ParticipantsRequest,
SettingsSecurityChangeInfo,
} from '@waha/structures/groups.dto';
@@ -75,6 +76,7 @@ import {
import { PaginatorInMemory } from '@waha/utils/Paginator';
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
import { SingleDelayedJobRunner } from '@waha/utils/SingleDelayedJobRunner';
import * as lodash from 'lodash';
import { fromEvent, merge, mergeMap, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import {
@@ -789,10 +791,25 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return groupChat.setMessagesAdminsOnly(value);
}
public getGroups() {
return this.whatsapp
.getChats()
.then((chats) => chats.filter((chat) => chat.isGroup));
public async getGroups(pagination: PaginationParams) {
const chats = await this.whatsapp.getChats();
const groups = lodash.filter(chats, (chat) => chat.isGroup);
switch (pagination.sortBy) {
case GroupSortField.ID:
pagination.sortBy = 'id._serialized';
break;
case GroupSortField.SUBJECT:
pagination.sortBy = 'groupMetadata.subject';
break;
}
const paginator = new PaginatorInMemory(pagination);
return paginator.apply(groups);
}
public async refreshGroups(): Promise<boolean> {
return true;
}
public getGroup(id) {
+26 -1
View File
@@ -1,5 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsString } from 'class-validator';
import { BooleanString } from '@waha/nestjs/validation/BooleanString';
import { Transform } from 'class-transformer';
import {
IsArray,
IsBoolean,
IsEnum,
IsOptional,
IsString,
} from 'class-validator';
import { PaginationParams } from './pagination.dto';
/**
* Structures
@@ -46,3 +56,18 @@ export class CreateGroupRequest {
@IsArray()
participants: Array<Participant>;
}
export enum GroupSortField {
ID = 'id',
SUBJECT = 'subject',
}
export class GroupsPaginationParams extends PaginationParams {
@ApiProperty({
description: 'Sort by field',
enum: GroupSortField,
})
@IsOptional()
@IsEnum(GroupSortField)
sortBy?: string;
}
+1 -1
View File
@@ -33,7 +33,7 @@ export function getEngineName(): string {
}
export const VERSION: WAHAEnvironment = {
version: '2024.12.1',
version: '2024.12.3',
engine: getEngineName(),
tier: getWAHAVersion(),
browser: getBrowserExecutablePath(),
+2 -2
View File
@@ -7,7 +7,7 @@ __metadata:
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-678":
version: 6.7.8
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=26ec38da416e49b111bd67f3a33e92b03c962494"
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=ea7f0f4365508d272809458b3e9094c7bb56cf3a"
dependencies:
"@adiwajshing/keyed-db": ^0.2.4
"@hapi/boom": ^9.1.3
@@ -39,7 +39,7 @@ __metadata:
optional: true
sharp:
optional: true
checksum: 290834568315317c42d625d8a0974f0b65f6c83a4f5ae8398e2c3155edc8969f33b3e60325a7eb22a28aca446fd83b0ad5367e2f285ca9352fa73c8a0437b75e
checksum: c765057d3978dae6e25218324f2e1d969a0173822b3a62f4677342cb94a08feaefa936d0ed6effb34bc2a5a340a938c51d7ac9dff8e6ecaf121d8e6dfa950119
languageName: node
linkType: hard