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
|
// auth.*, daemon.*, events.*: they work even when the session is not ready.
import { WaError } from '../rpc.js';
export const EVENTS = [
'qr', 'code', 'authenticated', 'auth_failure', 'ready', 'disconnected', 'change_state', 'loading_screen',
'message', 'message_create', 'message_ack', 'message_edit', 'message_revoke_everyone', 'message_revoke_me',
'message_reaction', 'media_uploaded', 'unread_count', 'chat_archived', 'chat_removed', 'contact_changed',
'group_join', 'group_leave', 'group_update', 'group_admin_changed', 'group_membership_request',
'call', 'vote_update',
];
export default {
'auth.status': {
description: 'WhatsApp session state (qr, code, authenticated, ready, ...) and linked account.',
ready: false,
handler: async (ctx) => ctx.status(),
},
'auth.pair': {
description: 'Requests a pairing code by phone number (alternative to the QR). ' +
'Enter it on the phone: Linked devices > Link with phone number instead.',
ready: false,
params: {
phone: { type: 'string', required: true, description: 'Number in international format, digits only (e.g. 5491122334455)' },
notify: { type: 'boolean', default: true, description: 'Show a notification on the phone' },
},
handler: async (ctx, p) => {
const st = ctx.status().state;
if (st === 'ready' || st === 'authenticated') {
throw new WaError('EINVAL', 'the session is already linked');
}
await ctx.waitState(['qr', 'code'], 60000);
const code = await ctx.client.requestPairingCode(p.phone.replace(/\D/g, ''), p.notify);
return { code };
},
},
'auth.logout': {
description: 'Logs out (unlinks this device) and deletes the local session.',
handler: async (ctx) => {
await ctx.client.logout();
return { ok: true };
},
},
'daemon.status': {
description: 'Daemon process information.',
ready: false,
handler: async (ctx) => ctx.daemonInfo(),
},
'daemon.stop': {
description: 'Stops the daemon (closes the browser; the session stays saved).',
ready: false,
handler: async (ctx) => {
setImmediate(() => ctx.shutdown('daemon.stop'));
return { ok: true };
},
},
'events.watch': {
description: 'Real-time event stream (NDJSON). Each event: {event, account, time, data}.',
ready: false,
stream: true,
params: {
events: { type: 'array', default: ['message'], description: `Eventos a escuchar, o ["all"]. Disponibles: ${EVENTS.join(', ')}` },
replay: { type: 'boolean', default: false, description: 'On connect, resend the current state (last qr/code, ready)' },
},
handler: async (ctx, p, conn) => {
const unknown = p.events.filter((e) => e !== 'all' && !EVENTS.includes(e));
if (unknown.length) throw new WaError('EINVAL', `eventos desconocidos: ${unknown.join(', ')}`);
ctx.subscribe(conn, p.events.includes('all') ? null : new Set(p.events), p.replay);
return ctx.STREAM;
},
},
};
|