1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import * as ser from '../serialize.js';
const chatParam = { type: 'chat', required: true, description: 'Chat: JID (549...@c.us, ...@g.us), phone number or exact name' };
const simple = (description, fn) => ({
description,
params: { chatId: chatParam },
handler: async (ctx, p) => fn(ctx, p.chatId),
});
export default {
'chats.list': {
description: 'Lists chats, most recent first.',
params: {
unread: { type: 'boolean', description: 'Only chats with unread messages' },
archived: { type: 'boolean', description: 'true: archived only; false: unarchived only' },
groups: { type: 'boolean', description: 'true: solo grupos; false: solo individuales' },
query: { type: 'string', description: 'Filters by name (case- and accent-insensitive)' },
limit: { type: 'integer', description: 'Maximum number of chats to return' },
},
columns: ['id', 'name', 'unreadCount', 'date', 'lastMessage.body'],
handler: async (ctx, p) => {
const norm = ctx.normalize;
let chats = (await ctx.client.getChats())
.filter((c) => p.unread === undefined || (c.unreadCount > 0) === p.unread)
.filter((c) => p.archived === undefined || Boolean(c.archived) === p.archived)
.filter((c) => p.groups === undefined || Boolean(c.isGroup) === p.groups)
.filter((c) => !p.query || norm(c.name || '').includes(norm(p.query)))
.sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
if (p.limit) chats = chats.slice(0, p.limit);
return chats.map((c) => ser.chat(c, ctx.ser));
},
},
'chats.get': {
description: 'Details of a chat (includes participants for groups).',
params: { chatId: chatParam },
handler: async (ctx, p) => {
const c = await ctx.getChat(p.chatId);
const out = ser.chat(c, ctx.ser);
if (c.isGroup) Object.assign(out, ser.group(c, ctx.ser));
return out;
},
},
'chats.resolve': {
description: 'Resolves a JID, number or name to a chatId (useful in scripts).',
params: { query: { type: 'string', required: true, description: 'JID, number or name' } },
handler: async (ctx, p) => {
const id = await ctx.resolveChat(p.query);
return { id, name: ctx.names(id) ?? null };
},
},
'chats.read': simple('Marks the chat as read (sends read receipts).', async (ctx, id) => ({
ok: await ctx.client.sendSeen(id),
})),
'chats.unread': simple('Marks the chat as unread.', async (ctx, id) => {
await ctx.client.markChatUnread(id);
return { ok: true };
}),
'chats.archive': simple('Archives the chat.', async (ctx, id) => ({ archived: await ctx.client.archiveChat(id) })),
'chats.unarchive': simple('Unarchives the chat.', async (ctx, id) => ({ archived: await ctx.client.unarchiveChat(id) })),
'chats.pin': simple('Pins the chat.', async (ctx, id) => ({ pinned: await ctx.client.pinChat(id) })),
'chats.unpin': simple('Unpins the chat.', async (ctx, id) => ({ pinned: await ctx.client.unpinChat(id) })),
'chats.unmute': simple('Unmutes the chat.', async (ctx, id) => ctx.client.unmuteChat(id)),
'chats.sync': simple('Asks the phone for the chat history (for chats with few loaded messages).',
async (ctx, id) => ({ ok: await ctx.client.syncHistory(id) })),
'chats.mute': {
description: 'Mutes the chat, forever or until a date.',
params: {
chatId: chatParam,
until: { type: 'string', description: 'ISO 8601 date or epoch seconds; omitted = forever' },
},
handler: async (ctx, p) => {
let date;
if (p.until) {
date = /^\d+$/.test(p.until) ? new Date(Number(p.until) * 1000) : new Date(p.until);
if (Number.isNaN(date.getTime())) throw new ctx.WaError('EINVAL', `invalid date: ${p.until}`);
}
return ctx.client.muteChat(p.chatId, date);
},
},
};
|