diff options
Diffstat (limited to 'src/api/chats.js')
| -rw-r--r-- | src/api/chats.js | 85 |
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); + }, + }, +}; |