@arcaelas/whatsapp 8.0.0 → 8.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/lib/chat/index.d.ts +3 -4
- package/build/cjs/lib/contact/index.d.ts +21 -0
- package/build/cjs/lib/contact/index.js +11 -0
- package/build/cjs/lib/message/index.d.ts +26 -0
- package/build/cjs/lib/message/index.js +19 -0
- package/build/cjs/lib/whatsapp/index.d.ts +1 -1
- package/build/cjs/lib/whatsapp/index.js +49 -2
- package/build/esm/lib/chat/index.d.ts +3 -4
- package/build/esm/lib/contact/index.d.ts +21 -0
- package/build/esm/lib/contact/index.js +11 -0
- package/build/esm/lib/message/index.d.ts +26 -0
- package/build/esm/lib/message/index.js +19 -0
- package/build/esm/lib/whatsapp/index.d.ts +1 -1
- package/build/esm/lib/whatsapp/index.js +50 -3
- package/package.json +1 -1
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Chat entity — individual and group conversations.
|
|
5
5
|
*/
|
|
6
6
|
import type { WASocket } from 'baileys';
|
|
7
|
-
import type Contact from '../../lib/contact';
|
|
8
7
|
import type Message from '../../lib/message';
|
|
9
8
|
import { type Engine } from '../../lib/store';
|
|
10
9
|
import type WhatsApp from '../../lib/whatsapp';
|
|
@@ -87,7 +86,7 @@ export declare function chat(init: {
|
|
|
87
86
|
* @param limit - Tamaño de página / Page size
|
|
88
87
|
* @returns Página de contactos / Contact page
|
|
89
88
|
*/
|
|
90
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
89
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
91
90
|
/**
|
|
92
91
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
93
92
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -221,7 +220,7 @@ export declare function chat(init: {
|
|
|
221
220
|
* @param limit - Tamaño de página / Page size
|
|
222
221
|
* @returns Página de contactos / Contact page
|
|
223
222
|
*/
|
|
224
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
223
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
225
224
|
/**
|
|
226
225
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
227
226
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -354,7 +353,7 @@ export declare function chat(init: {
|
|
|
354
353
|
* @param limit - Tamaño de página / Page size
|
|
355
354
|
* @returns Página de contactos / Contact page
|
|
356
355
|
*/
|
|
357
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
356
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
358
357
|
/**
|
|
359
358
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
360
359
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -76,6 +76,13 @@ export declare function contact(init: Init): {
|
|
|
76
76
|
img_url?: string | null;
|
|
77
77
|
status?: string | null;
|
|
78
78
|
}): {
|
|
79
|
+
/**
|
|
80
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
81
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
82
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
83
|
+
* because the account announces itself through either depending on the chat.
|
|
84
|
+
*/
|
|
85
|
+
get me(): boolean;
|
|
79
86
|
/**
|
|
80
87
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
81
88
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -132,6 +139,13 @@ export declare function contact(init: Init): {
|
|
|
132
139
|
* @returns Contacto, o null si no existe en WhatsApp / Contact, or null when not on WhatsApp
|
|
133
140
|
*/
|
|
134
141
|
get(uid: string | number): Promise<{
|
|
142
|
+
/**
|
|
143
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
144
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
145
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
146
|
+
* because the account announces itself through either depending on the chat.
|
|
147
|
+
*/
|
|
148
|
+
get me(): boolean;
|
|
135
149
|
/**
|
|
136
150
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
137
151
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -187,6 +201,13 @@ export declare function contact(init: Init): {
|
|
|
187
201
|
* @returns Página de contactos / Contact page
|
|
188
202
|
*/
|
|
189
203
|
list(offset?: number, limit?: number): Promise<{
|
|
204
|
+
/**
|
|
205
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
206
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
207
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
208
|
+
* because the account announces itself through either depending on the chat.
|
|
209
|
+
*/
|
|
210
|
+
get me(): boolean;
|
|
190
211
|
/**
|
|
191
212
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
192
213
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -58,6 +58,17 @@ exports.default = Contact;
|
|
|
58
58
|
*/
|
|
59
59
|
function contact(init) {
|
|
60
60
|
class _Contact extends Contact {
|
|
61
|
+
/**
|
|
62
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
63
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
64
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
65
|
+
* because the account announces itself through either depending on the chat.
|
|
66
|
+
*/
|
|
67
|
+
get me() {
|
|
68
|
+
const user = init.socket.user;
|
|
69
|
+
const mine = [user?.id, user?.lid].filter((id) => Boolean(id)).map((id) => (id.split(':')[0] ?? '').split('@')[0]);
|
|
70
|
+
return [this.jid, this.lid, this._raw.id].some((id) => id && mine.includes((id.split('@')[0] ?? '')));
|
|
71
|
+
}
|
|
61
72
|
/**
|
|
62
73
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
63
74
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -63,6 +63,12 @@ export default class Message {
|
|
|
63
63
|
emoji: string;
|
|
64
64
|
at: number;
|
|
65
65
|
}[];
|
|
66
|
+
responses?: {
|
|
67
|
+
author: string;
|
|
68
|
+
response: 'going' | 'not_going' | 'maybe';
|
|
69
|
+
guests: number;
|
|
70
|
+
at: number;
|
|
71
|
+
}[];
|
|
66
72
|
viewed?: boolean | null;
|
|
67
73
|
raw: WAMessage;
|
|
68
74
|
};
|
|
@@ -402,6 +408,20 @@ export declare class VCard extends Message {
|
|
|
402
408
|
export declare class Event extends Message {
|
|
403
409
|
/** @internal Bloque del evento en el raw. / Raw event block. */
|
|
404
410
|
get _event(): proto.Message.IEventMessage | null | undefined;
|
|
411
|
+
/** Asistentes confirmados, acompañantes incluidos. / Confirmed attendees, companions included. */
|
|
412
|
+
get going(): number;
|
|
413
|
+
/**
|
|
414
|
+
* Respuestas de asistencia al evento, con el nombre resuelto de cada contacto y en orden
|
|
415
|
+
* de llegada — la última es la más reciente.
|
|
416
|
+
* Attendance responses, with each contact's resolved name, in arrival order — the last one
|
|
417
|
+
* is the most recent.
|
|
418
|
+
*/
|
|
419
|
+
attendees(): Promise<{
|
|
420
|
+
name: string;
|
|
421
|
+
contact: string;
|
|
422
|
+
response: 'going' | 'not_going' | 'maybe';
|
|
423
|
+
guests: number;
|
|
424
|
+
}[]>;
|
|
405
425
|
/** Nombre del evento. / Event name. */
|
|
406
426
|
get name(): string;
|
|
407
427
|
/** Inicio en ISO UTC. / Start as ISO UTC. */
|
|
@@ -460,6 +480,12 @@ export declare function message(init: Init): {
|
|
|
460
480
|
emoji: string;
|
|
461
481
|
at: number;
|
|
462
482
|
}[];
|
|
483
|
+
responses?: {
|
|
484
|
+
author: string;
|
|
485
|
+
response: "going" | "not_going" | "maybe";
|
|
486
|
+
guests: number;
|
|
487
|
+
at: number;
|
|
488
|
+
}[];
|
|
463
489
|
viewed?: boolean | null;
|
|
464
490
|
raw: WAMessage;
|
|
465
491
|
};
|
|
@@ -677,6 +677,25 @@ exports.VCard = VCard;
|
|
|
677
677
|
class Event extends Message {
|
|
678
678
|
/** @internal Bloque del evento en el raw. / Raw event block. */
|
|
679
679
|
get _event() { return this._raw.raw.message?.eventMessage; }
|
|
680
|
+
/** Asistentes confirmados, acompañantes incluidos. / Confirmed attendees, companions included. */
|
|
681
|
+
get going() {
|
|
682
|
+
return (this._raw.responses ?? []).filter((entry) => entry.response === 'going').reduce((sum, entry) => sum + 1 + entry.guests, 0);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Respuestas de asistencia al evento, con el nombre resuelto de cada contacto y en orden
|
|
686
|
+
* de llegada — la última es la más reciente.
|
|
687
|
+
* Attendance responses, with each contact's resolved name, in arrival order — the last one
|
|
688
|
+
* is the most recent.
|
|
689
|
+
*/
|
|
690
|
+
async attendees() {
|
|
691
|
+
const rows = [];
|
|
692
|
+
for (const entry of this._raw.responses ?? []) {
|
|
693
|
+
const who = await this._init.wa.Contact.get(entry.author).catch(() => null);
|
|
694
|
+
const contact = (who?.phone ?? entry.author.split('@')[0].split(':')[0]);
|
|
695
|
+
rows.push({ name: who?.name ?? contact, contact, response: entry.response, guests: entry.guests });
|
|
696
|
+
}
|
|
697
|
+
return rows;
|
|
698
|
+
}
|
|
680
699
|
/** Nombre del evento. / Event name. */
|
|
681
700
|
get name() { return this._event?.name ?? ''; }
|
|
682
701
|
/** Inicio en ISO UTC. / Start as ISO UTC. */
|
|
@@ -109,7 +109,7 @@ interface EventMap {
|
|
|
109
109
|
'message:created': [Message, ChatInstance, WhatsApp];
|
|
110
110
|
'message:updated': [Message, ChatInstance, WhatsApp];
|
|
111
111
|
'message:deleted': [Message, ChatInstance, WhatsApp];
|
|
112
|
-
'message:reacted': [Message, ChatInstance, string, WhatsApp];
|
|
112
|
+
'message:reacted': [Message, ChatInstance, string, ContactInstance, WhatsApp];
|
|
113
113
|
'message:starred': [Message, ChatInstance, WhatsApp];
|
|
114
114
|
'message:unstarred': [Message, ChatInstance, WhatsApp];
|
|
115
115
|
'message:forwarded': [Message, ChatInstance, WhatsApp];
|
|
@@ -578,7 +578,15 @@ class WhatsApp {
|
|
|
578
578
|
];
|
|
579
579
|
await engine.set(found.path, (0, store_1.serialize)(found.doc), found.doc.created_at);
|
|
580
580
|
const instance = new message_1.default(init, found.doc);
|
|
581
|
-
|
|
581
|
+
// Quién reaccionó viaja en el evento: sin él, distinguir la
|
|
582
|
+
// reacción del usuario del eco de una propia obligaba a cada
|
|
583
|
+
// consumidor a llevar su propio registro de ecos con timeouts.
|
|
584
|
+
// Who reacted travels in the event: without it, telling the
|
|
585
|
+
// user's reaction from the echo of an own one forced every
|
|
586
|
+
// consumer to keep its own echo ledger with timeouts.
|
|
587
|
+
const who = await canonical(author);
|
|
588
|
+
const card = (0, store_1.deserialize)(await engine.get(`/contact/${who}`));
|
|
589
|
+
this.emit('message:reacted', instance, await instance.chat(), emoji, new this.Contact(card ?? { id: who, lid: null, name: null, notify: null, verified_name: null, img_url: null, status: null }), this);
|
|
582
590
|
}
|
|
583
591
|
continue;
|
|
584
592
|
}
|
|
@@ -634,10 +642,49 @@ class WhatsApp {
|
|
|
634
642
|
this.emit('feed:created', new status_1.Feed(init, doc), this);
|
|
635
643
|
continue;
|
|
636
644
|
}
|
|
645
|
+
if (kind === 'encEventResponseMessage') {
|
|
646
|
+
const enc = msg.message?.encEventResponseMessage;
|
|
647
|
+
const key = enc?.eventCreationMessageKey;
|
|
648
|
+
const found = key?.id ? ((key.remoteJid ? await locate(key.remoteJid, key.id) : null) ?? (await locate(cid, key.id))) : null;
|
|
649
|
+
const raw_secret = found?.doc.raw.message?.messageContextInfo?.messageSecret;
|
|
650
|
+
const secret = typeof raw_secret === 'string' ? Buffer.from(raw_secret, 'base64') : raw_secret;
|
|
651
|
+
if (found && secret && enc?.encPayload && enc.encIv) {
|
|
652
|
+
const mine = [socket.user?.lid, socket.user?.id];
|
|
653
|
+
const theirs = (from) => [from.remoteJid, from.participant, from.remoteJidAlt];
|
|
654
|
+
const responders = (msg.key.fromMe ? mine : theirs(msg.key)).filter((id) => Boolean(id));
|
|
655
|
+
const creators = (found.doc.raw.key?.fromMe ? mine : theirs(found.doc.raw.key ?? {})).filter((id) => Boolean(id));
|
|
656
|
+
for (const pair of responders.flatMap((who) => creators.map((creator) => [who, creator]))) {
|
|
657
|
+
try {
|
|
658
|
+
const parsed = (0, baileys_1.decryptEventResponse)({ encPayload: enc.encPayload, encIv: enc.encIv }, {
|
|
659
|
+
eventCreatorJid: (0, baileys_1.jidNormalizedUser)(pair[1]),
|
|
660
|
+
eventMsgId: found.doc.id,
|
|
661
|
+
eventEncKey: secret,
|
|
662
|
+
responderJid: (0, baileys_1.jidNormalizedUser)(pair[0]),
|
|
663
|
+
});
|
|
664
|
+
const response = { 1: 'going', 2: 'not_going', 3: 'maybe' }[parsed.response];
|
|
665
|
+
if (response) {
|
|
666
|
+
const author = await canonical((0, baileys_1.jidNormalizedUser)((msg.key.fromMe ? socket.user?.id : msg.key.participant ?? cid) ?? cid));
|
|
667
|
+
found.doc.responses = [
|
|
668
|
+
...(found.doc.responses ?? []).filter((entry) => entry.author !== author),
|
|
669
|
+
{ author, response, guests: Number(parsed.extraGuestCount ?? 0), at: (Number(msg.messageTimestamp) || Math.floor(Date.now() / 1_000)) * 1_000 },
|
|
670
|
+
];
|
|
671
|
+
await engine.set(found.path, (0, store_1.serialize)(found.doc), found.doc.created_at);
|
|
672
|
+
const instance = new message_1.default(init, found.doc);
|
|
673
|
+
this.emit('message:updated', instance, await instance.chat(), this);
|
|
674
|
+
}
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
/* identidad equivocada / wrong identity */
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
637
684
|
if (kind === 'pollUpdateMessage') {
|
|
638
685
|
const key = msg.message?.pollUpdateMessage?.pollCreationMessageKey;
|
|
639
686
|
const vote = msg.message?.pollUpdateMessage?.vote;
|
|
640
|
-
const found = key?.id
|
|
687
|
+
const found = key?.id ? ((key.remoteJid ? await locate(key.remoteJid, key.id) : null) ?? (await locate(cid, key.id))) : null;
|
|
641
688
|
const raw_secret = found?.doc.raw.message?.messageContextInfo?.messageSecret;
|
|
642
689
|
const secret = typeof raw_secret === 'string' ? Buffer.from(raw_secret, 'base64') : raw_secret;
|
|
643
690
|
if (found && secret && vote?.encPayload && vote.encIv) {
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Chat entity — individual and group conversations.
|
|
5
5
|
*/
|
|
6
6
|
import type { WASocket } from 'baileys';
|
|
7
|
-
import type Contact from '../../lib/contact/index.js';
|
|
8
7
|
import type Message from '../../lib/message/index.js';
|
|
9
8
|
import { type Engine } from '../../lib/store/index.js';
|
|
10
9
|
import type WhatsApp from '../../lib/whatsapp/index.js';
|
|
@@ -87,7 +86,7 @@ export declare function chat(init: {
|
|
|
87
86
|
* @param limit - Tamaño de página / Page size
|
|
88
87
|
* @returns Página de contactos / Contact page
|
|
89
88
|
*/
|
|
90
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
89
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
91
90
|
/**
|
|
92
91
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
93
92
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -221,7 +220,7 @@ export declare function chat(init: {
|
|
|
221
220
|
* @param limit - Tamaño de página / Page size
|
|
222
221
|
* @returns Página de contactos / Contact page
|
|
223
222
|
*/
|
|
224
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
223
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
225
224
|
/**
|
|
226
225
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
227
226
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -354,7 +353,7 @@ export declare function chat(init: {
|
|
|
354
353
|
* @param limit - Tamaño de página / Page size
|
|
355
354
|
* @returns Página de contactos / Contact page
|
|
356
355
|
*/
|
|
357
|
-
members(offset?: number, limit?: number): Promise<Contact[]>;
|
|
356
|
+
members(offset?: number, limit?: number): Promise<InstanceType<typeof init.wa.Contact>[]>;
|
|
358
357
|
/**
|
|
359
358
|
* Descripción: el asunto del grupo o, en un 1:1, la bio del contacto. Es asíncrono
|
|
360
359
|
* porque ninguna de las dos vive en el documento del chat.
|
|
@@ -76,6 +76,13 @@ export declare function contact(init: Init): {
|
|
|
76
76
|
img_url?: string | null;
|
|
77
77
|
status?: string | null;
|
|
78
78
|
}): {
|
|
79
|
+
/**
|
|
80
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
81
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
82
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
83
|
+
* because the account announces itself through either depending on the chat.
|
|
84
|
+
*/
|
|
85
|
+
get me(): boolean;
|
|
79
86
|
/**
|
|
80
87
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
81
88
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -132,6 +139,13 @@ export declare function contact(init: Init): {
|
|
|
132
139
|
* @returns Contacto, o null si no existe en WhatsApp / Contact, or null when not on WhatsApp
|
|
133
140
|
*/
|
|
134
141
|
get(uid: string | number): Promise<{
|
|
142
|
+
/**
|
|
143
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
144
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
145
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
146
|
+
* because the account announces itself through either depending on the chat.
|
|
147
|
+
*/
|
|
148
|
+
get me(): boolean;
|
|
135
149
|
/**
|
|
136
150
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
137
151
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -187,6 +201,13 @@ export declare function contact(init: Init): {
|
|
|
187
201
|
* @returns Página de contactos / Contact page
|
|
188
202
|
*/
|
|
189
203
|
list(offset?: number, limit?: number): Promise<{
|
|
204
|
+
/**
|
|
205
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
206
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
207
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
208
|
+
* because the account announces itself through either depending on the chat.
|
|
209
|
+
*/
|
|
210
|
+
get me(): boolean;
|
|
190
211
|
/**
|
|
191
212
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
192
213
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -53,6 +53,17 @@ export default class Contact {
|
|
|
53
53
|
*/
|
|
54
54
|
export function contact(init) {
|
|
55
55
|
class _Contact extends Contact {
|
|
56
|
+
/**
|
|
57
|
+
* true cuando este contacto es la propia cuenta. La comparación cubre JID y LID porque
|
|
58
|
+
* la cuenta se anuncia por cualquiera de los dos según el chat.
|
|
59
|
+
* true when this contact is the account itself. The comparison covers JID and LID
|
|
60
|
+
* because the account announces itself through either depending on the chat.
|
|
61
|
+
*/
|
|
62
|
+
get me() {
|
|
63
|
+
const user = init.socket.user;
|
|
64
|
+
const mine = [user?.id, user?.lid].filter((id) => Boolean(id)).map((id) => (id.split(':')[0] ?? '').split('@')[0]);
|
|
65
|
+
return [this.jid, this.lid, this._raw.id].some((id) => id && mine.includes((id.split('@')[0] ?? '')));
|
|
66
|
+
}
|
|
56
67
|
/**
|
|
57
68
|
* Chat 1:1 del contacto: el persistido, o una instancia mínima.
|
|
58
69
|
* The contact's 1:1 chat: the persisted one, or a minimal instance.
|
|
@@ -63,6 +63,12 @@ export default class Message {
|
|
|
63
63
|
emoji: string;
|
|
64
64
|
at: number;
|
|
65
65
|
}[];
|
|
66
|
+
responses?: {
|
|
67
|
+
author: string;
|
|
68
|
+
response: 'going' | 'not_going' | 'maybe';
|
|
69
|
+
guests: number;
|
|
70
|
+
at: number;
|
|
71
|
+
}[];
|
|
66
72
|
viewed?: boolean | null;
|
|
67
73
|
raw: WAMessage;
|
|
68
74
|
};
|
|
@@ -402,6 +408,20 @@ export declare class VCard extends Message {
|
|
|
402
408
|
export declare class Event extends Message {
|
|
403
409
|
/** @internal Bloque del evento en el raw. / Raw event block. */
|
|
404
410
|
get _event(): proto.Message.IEventMessage | null | undefined;
|
|
411
|
+
/** Asistentes confirmados, acompañantes incluidos. / Confirmed attendees, companions included. */
|
|
412
|
+
get going(): number;
|
|
413
|
+
/**
|
|
414
|
+
* Respuestas de asistencia al evento, con el nombre resuelto de cada contacto y en orden
|
|
415
|
+
* de llegada — la última es la más reciente.
|
|
416
|
+
* Attendance responses, with each contact's resolved name, in arrival order — the last one
|
|
417
|
+
* is the most recent.
|
|
418
|
+
*/
|
|
419
|
+
attendees(): Promise<{
|
|
420
|
+
name: string;
|
|
421
|
+
contact: string;
|
|
422
|
+
response: 'going' | 'not_going' | 'maybe';
|
|
423
|
+
guests: number;
|
|
424
|
+
}[]>;
|
|
405
425
|
/** Nombre del evento. / Event name. */
|
|
406
426
|
get name(): string;
|
|
407
427
|
/** Inicio en ISO UTC. / Start as ISO UTC. */
|
|
@@ -460,6 +480,12 @@ export declare function message(init: Init): {
|
|
|
460
480
|
emoji: string;
|
|
461
481
|
at: number;
|
|
462
482
|
}[];
|
|
483
|
+
responses?: {
|
|
484
|
+
author: string;
|
|
485
|
+
response: "going" | "not_going" | "maybe";
|
|
486
|
+
guests: number;
|
|
487
|
+
at: number;
|
|
488
|
+
}[];
|
|
463
489
|
viewed?: boolean | null;
|
|
464
490
|
raw: WAMessage;
|
|
465
491
|
};
|
|
@@ -660,6 +660,25 @@ export class VCard extends Message {
|
|
|
660
660
|
export class Event extends Message {
|
|
661
661
|
/** @internal Bloque del evento en el raw. / Raw event block. */
|
|
662
662
|
get _event() { return this._raw.raw.message?.eventMessage; }
|
|
663
|
+
/** Asistentes confirmados, acompañantes incluidos. / Confirmed attendees, companions included. */
|
|
664
|
+
get going() {
|
|
665
|
+
return (this._raw.responses ?? []).filter((entry) => entry.response === 'going').reduce((sum, entry) => sum + 1 + entry.guests, 0);
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Respuestas de asistencia al evento, con el nombre resuelto de cada contacto y en orden
|
|
669
|
+
* de llegada — la última es la más reciente.
|
|
670
|
+
* Attendance responses, with each contact's resolved name, in arrival order — the last one
|
|
671
|
+
* is the most recent.
|
|
672
|
+
*/
|
|
673
|
+
async attendees() {
|
|
674
|
+
const rows = [];
|
|
675
|
+
for (const entry of this._raw.responses ?? []) {
|
|
676
|
+
const who = await this._init.wa.Contact.get(entry.author).catch(() => null);
|
|
677
|
+
const contact = (who?.phone ?? entry.author.split('@')[0].split(':')[0]);
|
|
678
|
+
rows.push({ name: who?.name ?? contact, contact, response: entry.response, guests: entry.guests });
|
|
679
|
+
}
|
|
680
|
+
return rows;
|
|
681
|
+
}
|
|
663
682
|
/** Nombre del evento. / Event name. */
|
|
664
683
|
get name() { return this._event?.name ?? ''; }
|
|
665
684
|
/** Inicio en ISO UTC. / Start as ISO UTC. */
|
|
@@ -109,7 +109,7 @@ interface EventMap {
|
|
|
109
109
|
'message:created': [Message, ChatInstance, WhatsApp];
|
|
110
110
|
'message:updated': [Message, ChatInstance, WhatsApp];
|
|
111
111
|
'message:deleted': [Message, ChatInstance, WhatsApp];
|
|
112
|
-
'message:reacted': [Message, ChatInstance, string, WhatsApp];
|
|
112
|
+
'message:reacted': [Message, ChatInstance, string, ContactInstance, WhatsApp];
|
|
113
113
|
'message:starred': [Message, ChatInstance, WhatsApp];
|
|
114
114
|
'message:unstarred': [Message, ChatInstance, WhatsApp];
|
|
115
115
|
'message:forwarded': [Message, ChatInstance, WhatsApp];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Browsers, decryptPollVote, DisconnectReason, downloadMediaMessage, fetchLatestBaileysVersion, getContentType, initAuthCreds, jidNormalizedUser, makeWASocket, proto, updateMessageWithPollUpdate, } from 'baileys';
|
|
1
|
+
import { Browsers, decryptEventResponse, decryptPollVote, DisconnectReason, downloadMediaMessage, fetchLatestBaileysVersion, getContentType, initAuthCreds, jidNormalizedUser, makeWASocket, proto, updateMessageWithPollUpdate, } from 'baileys';
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
3
|
import pino from 'pino';
|
|
4
4
|
import * as QRCode from 'qrcode';
|
|
@@ -540,7 +540,15 @@ export default class WhatsApp {
|
|
|
540
540
|
];
|
|
541
541
|
await engine.set(found.path, serialize(found.doc), found.doc.created_at);
|
|
542
542
|
const instance = new Message(init, found.doc);
|
|
543
|
-
|
|
543
|
+
// Quién reaccionó viaja en el evento: sin él, distinguir la
|
|
544
|
+
// reacción del usuario del eco de una propia obligaba a cada
|
|
545
|
+
// consumidor a llevar su propio registro de ecos con timeouts.
|
|
546
|
+
// Who reacted travels in the event: without it, telling the
|
|
547
|
+
// user's reaction from the echo of an own one forced every
|
|
548
|
+
// consumer to keep its own echo ledger with timeouts.
|
|
549
|
+
const who = await canonical(author);
|
|
550
|
+
const card = deserialize(await engine.get(`/contact/${who}`));
|
|
551
|
+
this.emit('message:reacted', instance, await instance.chat(), emoji, new this.Contact(card ?? { id: who, lid: null, name: null, notify: null, verified_name: null, img_url: null, status: null }), this);
|
|
544
552
|
}
|
|
545
553
|
continue;
|
|
546
554
|
}
|
|
@@ -596,10 +604,49 @@ export default class WhatsApp {
|
|
|
596
604
|
this.emit('feed:created', new Feed(init, doc), this);
|
|
597
605
|
continue;
|
|
598
606
|
}
|
|
607
|
+
if (kind === 'encEventResponseMessage') {
|
|
608
|
+
const enc = msg.message?.encEventResponseMessage;
|
|
609
|
+
const key = enc?.eventCreationMessageKey;
|
|
610
|
+
const found = key?.id ? ((key.remoteJid ? await locate(key.remoteJid, key.id) : null) ?? (await locate(cid, key.id))) : null;
|
|
611
|
+
const raw_secret = found?.doc.raw.message?.messageContextInfo?.messageSecret;
|
|
612
|
+
const secret = typeof raw_secret === 'string' ? Buffer.from(raw_secret, 'base64') : raw_secret;
|
|
613
|
+
if (found && secret && enc?.encPayload && enc.encIv) {
|
|
614
|
+
const mine = [socket.user?.lid, socket.user?.id];
|
|
615
|
+
const theirs = (from) => [from.remoteJid, from.participant, from.remoteJidAlt];
|
|
616
|
+
const responders = (msg.key.fromMe ? mine : theirs(msg.key)).filter((id) => Boolean(id));
|
|
617
|
+
const creators = (found.doc.raw.key?.fromMe ? mine : theirs(found.doc.raw.key ?? {})).filter((id) => Boolean(id));
|
|
618
|
+
for (const pair of responders.flatMap((who) => creators.map((creator) => [who, creator]))) {
|
|
619
|
+
try {
|
|
620
|
+
const parsed = decryptEventResponse({ encPayload: enc.encPayload, encIv: enc.encIv }, {
|
|
621
|
+
eventCreatorJid: jidNormalizedUser(pair[1]),
|
|
622
|
+
eventMsgId: found.doc.id,
|
|
623
|
+
eventEncKey: secret,
|
|
624
|
+
responderJid: jidNormalizedUser(pair[0]),
|
|
625
|
+
});
|
|
626
|
+
const response = { 1: 'going', 2: 'not_going', 3: 'maybe' }[parsed.response];
|
|
627
|
+
if (response) {
|
|
628
|
+
const author = await canonical(jidNormalizedUser((msg.key.fromMe ? socket.user?.id : msg.key.participant ?? cid) ?? cid));
|
|
629
|
+
found.doc.responses = [
|
|
630
|
+
...(found.doc.responses ?? []).filter((entry) => entry.author !== author),
|
|
631
|
+
{ author, response, guests: Number(parsed.extraGuestCount ?? 0), at: (Number(msg.messageTimestamp) || Math.floor(Date.now() / 1_000)) * 1_000 },
|
|
632
|
+
];
|
|
633
|
+
await engine.set(found.path, serialize(found.doc), found.doc.created_at);
|
|
634
|
+
const instance = new Message(init, found.doc);
|
|
635
|
+
this.emit('message:updated', instance, await instance.chat(), this);
|
|
636
|
+
}
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
/* identidad equivocada / wrong identity */
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
599
646
|
if (kind === 'pollUpdateMessage') {
|
|
600
647
|
const key = msg.message?.pollUpdateMessage?.pollCreationMessageKey;
|
|
601
648
|
const vote = msg.message?.pollUpdateMessage?.vote;
|
|
602
|
-
const found = key?.id
|
|
649
|
+
const found = key?.id ? ((key.remoteJid ? await locate(key.remoteJid, key.id) : null) ?? (await locate(cid, key.id))) : null;
|
|
603
650
|
const raw_secret = found?.doc.raw.message?.messageContextInfo?.messageSecret;
|
|
604
651
|
const secret = typeof raw_secret === 'string' ? Buffer.from(raw_secret, 'base64') : raw_secret;
|
|
605
652
|
if (found && secret && vote?.encPayload && vote.encIv) {
|