aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/contacts.js
blob: b7ef6df89f289b60d64ba5cd83eddbee9d1ca99d (plain)
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
86
import * as ser from '../serialize.js';

const contactParam = { type: 'chat', required: true, description: 'Contact: JID (549...@c.us), phone number or exact name' };

export default {
    'contacts.list': {
        description: 'Lists contacts (users; no groups).',
        params: {
            query: { type: 'string', description: 'Filters by name or number' },
            saved: { type: 'boolean', description: 'true: only contacts saved on the phone' },
            limit: { type: 'integer', description: 'Maximum to return' },
        },
        columns: ['id', 'displayName', 'number', 'isMyContact'],
        handler: async (ctx, p) => {
            const q = p.query && ctx.normalize(p.query);
            let list = (await ctx.client.getContacts())
                .filter((c) => !c.isGroup && c.id.server !== 'broadcast')
                .filter((c) => p.saved === undefined || Boolean(c.isMyContact) === p.saved)
                .map(ser.contact)
                .filter((c) => !q || [c.name, c.pushname, c.shortName, c.number]
                    .some((v) => v && ctx.normalize(v).includes(q)))
                .sort((a, b) => (a.displayName || '').localeCompare(b.displayName || ''));
            if (p.limit) list = list.slice(0, p.limit);
            return list;
        },
    },

    'contacts.get': {
        description: 'Details of a contact (includes "about").',
        params: { contactId: contactParam },
        handler: async (ctx, p) => {
            const c = await ctx.client.getContactById(p.contactId);
            const out = ser.contact(c);
            out.about = await c.getAbout().catch(() => null);
            return out;
        },
    },

    'contacts.resolve': {
        description: 'Checks whether a number is on WhatsApp and returns its JID.',
        params: { number: { type: 'string', required: true, description: 'International number (e.g. +54 9 11 2233-4455)' } },
        handler: async (ctx, p) => {
            const digits = p.number.replace(/\D/g, '');
            const id = await ctx.client.getNumberId(digits);
            return { number: digits, registered: Boolean(id), id: id?._serialized ?? null };
        },
    },

    'contacts.picture': {
        description: 'Profile picture URL (if privacy allows it).',
        params: { contactId: contactParam },
        handler: async (ctx, p) => ({ url: (await ctx.client.getProfilePicUrl(p.contactId)) ?? null }),
    },

    'groups.list': {
        description: 'Lists groups.',
        params: { query: { type: 'string', description: 'Filters by name' } },
        columns: ['id', 'name', 'participantCount', 'unreadCount', 'date'],
        handler: async (ctx, p) => (await ctx.client.getChats())
            .filter((c) => c.isGroup)
            .filter((c) => !p.query || ctx.normalize(c.name || '').includes(ctx.normalize(p.query)))
            .sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0))
            .map((c) => ser.chat(c, ctx.ser)),
    },

    'groups.get': {
        description: 'Details of a group: description, owner and participants.',
        params: { groupId: { ...contactParam, description: 'Grupo: JID (...@g.us) o nombre exacto' } },
        handler: async (ctx, p) => {
            const c = await ctx.getChat(p.groupId);
            if (!c.isGroup) throw new ctx.WaError('EINVAL', `${p.groupId} is not a group`);
            return ser.group(c, ctx.ser);
        },
    },

    'groups.invite': {
        description: 'Group invite link (requires being an admin).',
        params: { groupId: { ...contactParam, description: 'Grupo: JID (...@g.us) o nombre exacto' } },
        handler: async (ctx, p) => {
            const c = await ctx.getChat(p.groupId);
            if (!c.isGroup) throw new ctx.WaError('EINVAL', `${p.groupId} is not a group`);
            const code = await c.getInviteCode();
            return { code, link: `https://chat.whatsapp.com/${code}` };
        },
    },
};