aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/chats.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/chats.js')
-rw-r--r--src/api/chats.js85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/api/chats.js b/src/api/chats.js
new file mode 100644
index 0000000..c13564f
--- /dev/null
+++ b/src/api/chats.js
@@ -0,0 +1,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);
+ },
+ },
+};