@arcaelas/whatsapp 3.0.2 → 3.1.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.
Files changed (81) hide show
  1. package/package.json +1 -1
  2. package/build/cjs/decorators.d.ts +0 -9
  3. package/build/cjs/decorators.js +0 -26
  4. package/build/cjs/decorators.js.map +0 -1
  5. package/build/cjs/index.d.ts +0 -9
  6. package/build/cjs/index.js +0 -18
  7. package/build/cjs/index.js.map +0 -1
  8. package/build/cjs/lib/bot/decorator.d.ts +0 -77
  9. package/build/cjs/lib/bot/decorator.js +0 -219
  10. package/build/cjs/lib/bot/decorator.js.map +0 -1
  11. package/build/cjs/lib/bot/decorators.d.ts +0 -113
  12. package/build/cjs/lib/bot/decorators.js +0 -253
  13. package/build/cjs/lib/bot/decorators.js.map +0 -1
  14. package/build/cjs/lib/bot/index.d.ts +0 -3
  15. package/build/cjs/lib/bot/index.js +0 -20
  16. package/build/cjs/lib/bot/index.js.map +0 -1
  17. package/build/cjs/lib/chat/index.d.ts +0 -227
  18. package/build/cjs/lib/chat/index.js +0 -324
  19. package/build/cjs/lib/chat/index.js.map +0 -1
  20. package/build/cjs/lib/contact/index.d.ts +0 -203
  21. package/build/cjs/lib/contact/index.js +0 -226
  22. package/build/cjs/lib/contact/index.js.map +0 -1
  23. package/build/cjs/lib/message/index.d.ts +0 -237
  24. package/build/cjs/lib/message/index.js +0 -685
  25. package/build/cjs/lib/message/index.js.map +0 -1
  26. package/build/cjs/lib/store/engine/index.d.ts +0 -34
  27. package/build/cjs/lib/store/engine/index.js +0 -13
  28. package/build/cjs/lib/store/engine/index.js.map +0 -1
  29. package/build/cjs/lib/store/engine/lib/file_system/index.d.ts +0 -56
  30. package/build/cjs/lib/store/engine/lib/file_system/index.js +0 -160
  31. package/build/cjs/lib/store/engine/lib/file_system/index.js.map +0 -1
  32. package/build/cjs/lib/store/engine/lib/redis/index.d.ts +0 -82
  33. package/build/cjs/lib/store/engine/lib/redis/index.js +0 -132
  34. package/build/cjs/lib/store/engine/lib/redis/index.js.map +0 -1
  35. package/build/cjs/lib/store/index.d.ts +0 -22
  36. package/build/cjs/lib/store/index.js +0 -38
  37. package/build/cjs/lib/store/index.js.map +0 -1
  38. package/build/cjs/lib/whatsapp/index.d.ts +0 -179
  39. package/build/cjs/lib/whatsapp/index.js +0 -754
  40. package/build/cjs/lib/whatsapp/index.js.map +0 -1
  41. package/build/cjs/package.json +0 -1
  42. package/build/esm/decorators.d.ts +0 -9
  43. package/build/esm/decorators.js +0 -9
  44. package/build/esm/decorators.js.map +0 -1
  45. package/build/esm/index.d.ts +0 -9
  46. package/build/esm/index.js +0 -8
  47. package/build/esm/index.js.map +0 -1
  48. package/build/esm/lib/bot/decorator.d.ts +0 -77
  49. package/build/esm/lib/bot/decorator.js +0 -210
  50. package/build/esm/lib/bot/decorator.js.map +0 -1
  51. package/build/esm/lib/bot/decorators.d.ts +0 -113
  52. package/build/esm/lib/bot/decorators.js +0 -242
  53. package/build/esm/lib/bot/decorators.js.map +0 -1
  54. package/build/esm/lib/bot/index.d.ts +0 -3
  55. package/build/esm/lib/bot/index.js +0 -3
  56. package/build/esm/lib/bot/index.js.map +0 -1
  57. package/build/esm/lib/chat/index.d.ts +0 -227
  58. package/build/esm/lib/chat/index.js +0 -319
  59. package/build/esm/lib/chat/index.js.map +0 -1
  60. package/build/esm/lib/contact/index.d.ts +0 -203
  61. package/build/esm/lib/contact/index.js +0 -221
  62. package/build/esm/lib/contact/index.js.map +0 -1
  63. package/build/esm/lib/message/index.d.ts +0 -237
  64. package/build/esm/lib/message/index.js +0 -673
  65. package/build/esm/lib/message/index.js.map +0 -1
  66. package/build/esm/lib/store/engine/index.d.ts +0 -34
  67. package/build/esm/lib/store/engine/index.js +0 -8
  68. package/build/esm/lib/store/engine/index.js.map +0 -1
  69. package/build/esm/lib/store/engine/lib/file_system/index.d.ts +0 -56
  70. package/build/esm/lib/store/engine/lib/file_system/index.js +0 -156
  71. package/build/esm/lib/store/engine/lib/file_system/index.js.map +0 -1
  72. package/build/esm/lib/store/engine/lib/redis/index.d.ts +0 -82
  73. package/build/esm/lib/store/engine/lib/redis/index.js +0 -128
  74. package/build/esm/lib/store/engine/lib/redis/index.js.map +0 -1
  75. package/build/esm/lib/store/index.d.ts +0 -22
  76. package/build/esm/lib/store/index.js +0 -31
  77. package/build/esm/lib/store/index.js.map +0 -1
  78. package/build/esm/lib/whatsapp/index.d.ts +0 -179
  79. package/build/esm/lib/whatsapp/index.js +0 -714
  80. package/build/esm/lib/whatsapp/index.js.map +0 -1
  81. package/build/esm/package.json +0 -1
@@ -1,673 +0,0 @@
1
- /**
2
- * @file message/index.ts
3
- * @description Entidad Message — una sola clase base que recibe `{wa, doc}` en el constructor.
4
- * Subclases especializadas (Text, Image, Video, Audio, Gps, Poll) override `content()` según su tipo.
5
- */
6
- import { aesEncryptGCM, downloadMediaMessage, generateForwardMessageContent, generateMessageID, generateWAMessageFromContent, getAggregateVotesInPollMessage, getContentType, getKeyAuthor, hmacSign, jidNormalizedUser, proto, sha256, } from 'baileys';
7
- import { randomBytes } from 'node:crypto';
8
- import { Readable } from 'node:stream';
9
- import { Chat } from '../../lib/chat/index.js';
10
- import { deserialize, serialize } from '../../lib/store/index.js';
11
- export var MessageStatus;
12
- (function (MessageStatus) {
13
- MessageStatus[MessageStatus["ERROR"] = 0] = "ERROR";
14
- MessageStatus[MessageStatus["PENDING"] = 1] = "PENDING";
15
- MessageStatus[MessageStatus["SERVER_ACK"] = 2] = "SERVER_ACK";
16
- MessageStatus[MessageStatus["DELIVERED"] = 3] = "DELIVERED";
17
- MessageStatus[MessageStatus["READ"] = 4] = "READ";
18
- MessageStatus[MessageStatus["PLAYED"] = 5] = "PLAYED";
19
- })(MessageStatus || (MessageStatus = {}));
20
- const MESSAGE_TYPE_MAP = {
21
- conversation: 'text',
22
- extendedTextMessage: 'text',
23
- imageMessage: 'image',
24
- videoMessage: 'video',
25
- audioMessage: 'audio',
26
- locationMessage: 'location',
27
- liveLocationMessage: 'location',
28
- pollCreationMessage: 'poll',
29
- pollCreationMessageV2: 'poll',
30
- pollCreationMessageV3: 'poll',
31
- };
32
- /**
33
- * Construye el documento IMessage desde el raw de baileys.
34
- */
35
- export function build_message_doc(raw, self_id, edited = false) {
36
- const key = raw.key ?? {};
37
- const msg = raw.message ?? {};
38
- const unwrapped = msg.viewOnceMessage?.message ??
39
- msg.viewOnceMessageV2?.message ??
40
- msg.viewOnceMessageV2Extension?.message ??
41
- msg;
42
- const content_type = getContentType(unwrapped);
43
- const msg_type = MESSAGE_TYPE_MAP[content_type ?? ''] ?? 'text';
44
- const msg_content = unwrapped[content_type];
45
- const context_info = msg_content
46
- ?.contextInfo;
47
- const ephemeral_duration = raw.ephemeralDuration ?? context_info?.expiration;
48
- const deleted_at = raw.ephemeralStartTimestamp != null && ephemeral_duration != null
49
- ? (Number(raw.ephemeralStartTimestamp) + ephemeral_duration) * 1000
50
- : null;
51
- let mime = 'text/plain';
52
- if (msg_type === 'location' || msg_type === 'poll') {
53
- mime = 'application/json';
54
- }
55
- else if (msg_type !== 'text' && typeof msg_content === 'object') {
56
- mime = msg_content?.mimetype ?? 'application/octet-stream';
57
- }
58
- let caption = '';
59
- if (typeof msg_content === 'string') {
60
- caption = msg_content;
61
- }
62
- else if (msg_content) {
63
- caption =
64
- msg_content.caption ??
65
- msg_content.text ??
66
- msg_content.name ??
67
- '';
68
- }
69
- const author = key.fromMe && self_id
70
- ? jidNormalizedUser(self_id)
71
- : key.participant || key.remoteJidAlt || key.remoteJid || '';
72
- return {
73
- id: key.id ?? '',
74
- cid: key.remoteJidAlt ?? key.remoteJid ?? '',
75
- mid: context_info?.stanzaId ?? null,
76
- me: key.fromMe ?? false,
77
- type: msg_type,
78
- author,
79
- status: raw.status ?? MessageStatus.PENDING,
80
- starred: raw.starred ?? false,
81
- forwarded: context_info?.isForwarded ?? false,
82
- created_at: (Number(raw.messageTimestamp) || Math.floor(Date.now() / 1000)) * 1000,
83
- deleted_at,
84
- mime,
85
- caption,
86
- edited,
87
- raw,
88
- };
89
- }
90
- /**
91
- * Clase base del mensaje. Una sola clase — toda la API de instancia vive aquí.
92
- * Base message class. Single class — all instance API lives here.
93
- */
94
- export class Message {
95
- constructor(options) {
96
- this._wa = options.wa;
97
- this._doc = options.doc;
98
- }
99
- get id() {
100
- return this._doc.id;
101
- }
102
- get cid() {
103
- return this._doc.cid;
104
- }
105
- get type() {
106
- return this._doc.type;
107
- }
108
- /** JID del autor del mensaje. Para acceso síncrono sin hidratar el Contact. */
109
- get from() {
110
- return this._doc.author;
111
- }
112
- /** MIME type del contenido. `text/plain` para texto, `application/json` para location/poll, mimetype real para media. */
113
- get mime() {
114
- return this._doc.mime;
115
- }
116
- get mid() {
117
- return this._doc.mid;
118
- }
119
- get me() {
120
- return this._doc.me;
121
- }
122
- get caption() {
123
- return this._doc.caption;
124
- }
125
- get starred() {
126
- return this._doc.starred;
127
- }
128
- get forwarded() {
129
- return this._doc.forwarded;
130
- }
131
- get once() {
132
- return this._doc.deleted_at !== null;
133
- }
134
- get created_at() {
135
- return this._doc.created_at;
136
- }
137
- get deleted_at() {
138
- return this._doc.deleted_at;
139
- }
140
- get status() {
141
- return this._doc.status;
142
- }
143
- get edited() {
144
- return this._doc.edited;
145
- }
146
- /** Contacto del autor (resuelve vía `wa.Contact.get`; fallback a instancia mínima). */
147
- async author() {
148
- const { _wa, _doc } = this;
149
- const fetched = _doc.author ? await _wa.Contact.get(_doc.author) : null;
150
- return (fetched ??
151
- new _wa.Contact({
152
- id: _doc.author,
153
- lid: null,
154
- name: null,
155
- notify: null,
156
- verified_name: null,
157
- img_url: null,
158
- status: null,
159
- }, new _wa.Chat({ id: _doc.author, name: _doc.author.split('@')[0] })));
160
- }
161
- /** Chat al que pertenece el mensaje. */
162
- async chat() {
163
- const cached = deserialize(await this._wa.engine.get(`/chat/${this._doc.cid}`));
164
- return new this._wa.Chat(cached ?? { id: this._doc.cid, name: this._doc.cid.split('@')[0] });
165
- }
166
- /** Contenido sin parsear, directo del engine. Las subclases override según su tipo. */
167
- async content() {
168
- const cached = deserialize(await this._wa.engine.get(`/chat/${this._doc.cid}/message/${this._doc.id}/content`));
169
- return cached?.data ? Buffer.from(cached.data, 'base64') : Buffer.alloc(0);
170
- }
171
- /**
172
- * Devuelve un `Readable` con los bytes del mensaje. Para media (image/video/audio)
173
- * lee desde el cache del engine o, si falta, descarga desde baileys. Para text/location/poll
174
- * retorna el mismo binario que `content()` envuelto en un Readable.
175
- * Returns a `Readable` of the message bytes. For media (image/video/audio) it reads
176
- * from the engine cache or, if missing, downloads from baileys. For text/location/poll
177
- * it wraps the `content()` buffer in a Readable.
178
- */
179
- async stream() {
180
- return _media_stream(this);
181
- }
182
- /** Reacciona al mensaje (emoji vacío para retirar). */
183
- async react(emoji) {
184
- const { _wa, _doc } = this;
185
- let ok = false;
186
- if (_wa._socket) {
187
- await _wa._socket.sendMessage(_doc.cid, {
188
- react: { text: emoji, key: { remoteJid: _doc.cid, id: _doc.id, fromMe: _doc.me } },
189
- });
190
- ok = true;
191
- }
192
- return ok;
193
- }
194
- /** Reenvía el mensaje a un destino (CID, Chat o Contact). */
195
- async forward(target) {
196
- const { _wa, _doc } = this;
197
- const to_cid = typeof target === 'string' ? target : target instanceof Chat ? target.id : target.chat.id;
198
- let ok = false;
199
- if (_wa._socket) {
200
- const jid = await _wa._resolve_jid(to_cid);
201
- if (jid) {
202
- if (_doc.raw.message) {
203
- try {
204
- const wa_msg = generateWAMessageFromContent(jid, generateForwardMessageContent(_doc.raw, false), { userJid: _wa._socket.user?.id ?? '' });
205
- if (wa_msg.message && wa_msg.key?.id) {
206
- await _wa._socket.relayMessage(jid, wa_msg.message, { messageId: wa_msg.key.id });
207
- ok = true;
208
- }
209
- }
210
- catch {
211
- /* fallback below */
212
- }
213
- }
214
- if (!ok) {
215
- const buf = await this.content();
216
- if (buf.length > 0) {
217
- if (_doc.type === 'text') {
218
- ok = (await _wa.Message.text(jid, buf.toString())) !== null;
219
- }
220
- else if (_doc.type === 'image') {
221
- ok =
222
- (await _wa.Message.image(jid, buf, { caption: _doc.caption || undefined })) !==
223
- null;
224
- }
225
- else if (_doc.type === 'video') {
226
- ok =
227
- (await _wa.Message.video(jid, buf, { caption: _doc.caption || undefined })) !==
228
- null;
229
- }
230
- else if (_doc.type === 'audio') {
231
- ok = (await _wa.Message.audio(jid, buf)) !== null;
232
- }
233
- else if (_doc.type === 'location') {
234
- try {
235
- ok =
236
- (await _wa.Message.location(jid, JSON.parse(buf.toString()))) !== null;
237
- }
238
- catch {
239
- /* invalid payload */
240
- }
241
- }
242
- }
243
- }
244
- }
245
- }
246
- return ok;
247
- }
248
- /** Marca el mensaje como leído. */
249
- async seen() {
250
- const { _wa, _doc } = this;
251
- let ok = false;
252
- if (_wa._socket) {
253
- await _wa._socket.readMessages([
254
- { remoteJid: _doc.cid, id: _doc.id, participant: _doc.me ? undefined : _doc.author },
255
- ]);
256
- ok = true;
257
- }
258
- return ok;
259
- }
260
- /** Destaca/retira destacado del mensaje. */
261
- async star(value) {
262
- const { _wa: wa, _doc: doc } = this;
263
- let ok = false;
264
- if (wa._socket) {
265
- await wa._socket.chatModify({
266
- star: { messages: [{ id: doc.id, fromMe: doc.me }], star: value },
267
- }, doc.cid);
268
- doc.starred = value;
269
- await wa.engine.set(`/chat/${doc.cid}/message/${doc.id}`, serialize(doc));
270
- ok = true;
271
- }
272
- return ok;
273
- }
274
- /** Elimina el mensaje. `all=true` (default) borra para todos; `all=false` borra sólo en mi dispositivo. */
275
- async delete(all = true) {
276
- const { _wa: wa, _doc: doc } = this;
277
- let ok = false;
278
- if (wa._socket) {
279
- if (all) {
280
- await wa._socket.sendMessage(doc.cid, {
281
- delete: { remoteJid: doc.cid, id: doc.id, fromMe: doc.me },
282
- });
283
- }
284
- else {
285
- await wa._socket.chatModify({
286
- deleteForMe: {
287
- deleteMedia: false,
288
- key: { remoteJid: doc.cid, id: doc.id, fromMe: doc.me },
289
- timestamp: Date.now(),
290
- },
291
- }, doc.cid);
292
- }
293
- await wa.engine.unset(`/chat/${doc.cid}/message/${doc.id}`);
294
- ok = true;
295
- }
296
- return ok;
297
- }
298
- /** Edita el texto/caption del mensaje (solo propios editables). */
299
- async edit(text) {
300
- const { _wa: wa, _doc: doc } = this;
301
- let ok = false;
302
- if (wa._socket && doc.me) {
303
- await wa._socket.sendMessage(doc.cid, {
304
- text,
305
- edit: { remoteJid: doc.cid, id: doc.id, fromMe: true },
306
- });
307
- const content_type = getContentType(doc.raw.message ?? {});
308
- if (content_type === 'conversation') {
309
- doc.raw.message = { conversation: text };
310
- }
311
- else if (content_type === 'extendedTextMessage') {
312
- doc.raw.message = { extendedTextMessage: { text } };
313
- }
314
- doc.caption = text;
315
- doc.edited = true;
316
- await wa.engine.set(`/chat/${doc.cid}/message/${doc.id}`, serialize(doc));
317
- ok = true;
318
- }
319
- return ok;
320
- }
321
- /** Observa cambios sobre este mensaje. Retorna unsubscribe. / Watches this message. Returns unsubscribe. */
322
- watch(handler) {
323
- const cid = this.cid;
324
- const id = this.id;
325
- return this._wa.on('message:updated', (updated) => {
326
- if (updated.cid === cid && updated.id === id) {
327
- handler(updated);
328
- }
329
- });
330
- }
331
- /** Responde con texto. */
332
- async text(caption, opts = {}) {
333
- return this._wa.Message.text(this.cid, caption, { ...opts, mid: this.id });
334
- }
335
- /** Responde con imagen. */
336
- async image(buf, opts = {}) {
337
- return this._wa.Message.image(this.cid, buf, { ...opts, mid: this.id });
338
- }
339
- /** Responde con video. */
340
- async video(buf, opts = {}) {
341
- return this._wa.Message.video(this.cid, buf, { ...opts, mid: this.id });
342
- }
343
- /** Responde con audio. */
344
- async audio(buf, opts = {}) {
345
- return this._wa.Message.audio(this.cid, buf, { ...opts, mid: this.id });
346
- }
347
- /** Responde con ubicación. */
348
- async location(loc, opts = {}) {
349
- return this._wa.Message.location(this.cid, loc, { ...opts, mid: this.id });
350
- }
351
- /** Responde con encuesta. */
352
- async poll(poll, opts = {}) {
353
- return this._wa.Message.poll(this.cid, poll, { ...opts, mid: this.id });
354
- }
355
- }
356
- /**
357
- * Mensaje de texto. Override `content()` para retornar el caption como Buffer sin pasar por engine.
358
- * Text message. Overrides `content()` returning caption as Buffer directly.
359
- */
360
- export class Text extends Message {
361
- async content() {
362
- return Buffer.from(this.caption, 'utf-8');
363
- }
364
- }
365
- /** @internal Helper compartido por media classes: stream del binario (cache → download). */
366
- async function _media_stream(msg) {
367
- const wa = msg._wa;
368
- const doc = msg._doc;
369
- const cached = deserialize(await wa.engine.get(`/chat/${doc.cid}/message/${doc.id}/content`));
370
- if (cached?.data) {
371
- return Readable.from(Buffer.from(cached.data, 'base64'));
372
- }
373
- if (wa._socket) {
374
- try {
375
- return (await downloadMediaMessage(doc.raw, 'stream', {}));
376
- }
377
- catch {
378
- /* fallback empty */
379
- }
380
- }
381
- return Readable.from(Buffer.alloc(0));
382
- }
383
- /** @internal Acumula un Readable en Buffer. */
384
- async function _drain(readable) {
385
- const chunks = [];
386
- for await (const chunk of readable) {
387
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
388
- }
389
- return Buffer.concat(chunks);
390
- }
391
- /**
392
- * Mensaje de imagen. Hereda `stream()` de la clase base; `content()` drena el stream.
393
- * Image message. Inherits `stream()` from the base class; `content()` drains the stream.
394
- */
395
- export class Image extends Message {
396
- async content() {
397
- return _drain(await this.stream());
398
- }
399
- }
400
- /**
401
- * Mensaje de video. Hereda `stream()` de la clase base; `content()` drena el stream.
402
- * Video message. Inherits `stream()` from the base class; `content()` drains the stream.
403
- */
404
- export class Video extends Message {
405
- async content() {
406
- return _drain(await this.stream());
407
- }
408
- }
409
- /**
410
- * Mensaje de audio. Hereda `stream()` de la clase base; `content()` drena el stream.
411
- * `ptt` indica si es nota de voz (push-to-talk).
412
- * Audio message. Inherits `stream()` from the base class; `content()` drains the stream.
413
- * `ptt` flags voice notes.
414
- */
415
- export class Audio extends Message {
416
- /** true si es nota de voz (push-to-talk). / true if push-to-talk voice note. */
417
- get ptt() {
418
- return this._doc.raw.message?.audioMessage?.ptt === true;
419
- }
420
- async content() {
421
- return _drain(await this.stream());
422
- }
423
- }
424
- /**
425
- * Mensaje de ubicación. Agrega getters sync `lat`, `lng`, `link` derivados del raw.
426
- * Location message. Adds sync getters `lat`, `lng`, `link` derived from raw.
427
- */
428
- export class Gps extends Message {
429
- get _loc() {
430
- return this._doc.raw.message?.locationMessage ?? this._doc.raw.message?.liveLocationMessage;
431
- }
432
- /** Latitud en grados. / Latitude in degrees. */
433
- get lat() {
434
- return this._loc?.degreesLatitude ?? 0;
435
- }
436
- /** Longitud en grados. / Longitude in degrees. */
437
- get lng() {
438
- return this._loc?.degreesLongitude ?? 0;
439
- }
440
- /** URL de Google Maps apuntando a la coordenada. / Google Maps URL for the coordinate. */
441
- get link() {
442
- return `https://www.google.com/maps/@${this.lat},${this.lng},15z`;
443
- }
444
- /** true si es ubicación en tiempo real. / true when live location. */
445
- get live() {
446
- return Boolean(this._doc.raw.message?.liveLocationMessage);
447
- }
448
- }
449
- /**
450
- * Mensaje de encuesta. `caption` es la pregunta (heredada); agrega `options[]` con conteo y `multiple`.
451
- * Poll message. `caption` is the question (inherited); adds `options[]` with counts and `multiple`.
452
- */
453
- export class Poll extends Message {
454
- get _poll() {
455
- const m = this._doc.raw.message;
456
- return m?.pollCreationMessage ?? m?.pollCreationMessageV2 ?? m?.pollCreationMessageV3;
457
- }
458
- /** true si admite múltiples respuestas. / true if it accepts multiple answers. */
459
- get multiple() {
460
- return (this._poll?.selectableOptionsCount ?? 1) !== 1;
461
- }
462
- /** Opciones con conteo de votos actualizado. / Options with up-to-date vote counts. */
463
- get options() {
464
- const opts = this._poll?.options ?? [];
465
- const raw_updates = this._doc.raw.pollUpdates ?? [];
466
- // Normaliza selectedOptions de base64-string a Buffer (BufferJSON no reconstruye el tipo aquí)
467
- const updates = raw_updates.map((u) => ({
468
- ...u,
469
- vote: u.vote
470
- ? {
471
- ...u.vote,
472
- selectedOptions: (u.vote.selectedOptions ?? []).map((s) => typeof s === 'string' ? Buffer.from(s, 'base64') : s),
473
- }
474
- : u.vote,
475
- }));
476
- const aggregated = getAggregateVotesInPollMessage({ message: this._doc.raw.message ?? undefined, pollUpdates: updates }, this._wa._socket?.user?.id);
477
- const counts = new Map(aggregated.map((a) => [a.name, a.voters.length]));
478
- return opts.map((o) => ({
479
- content: o.optionName ?? '',
480
- count: counts.get(o.optionName ?? '') ?? 0,
481
- }));
482
- }
483
- /**
484
- * Vota en la encuesta. Acepta un índice o lista de índices (para `multiple`).
485
- * Votes in the poll. Accepts a single index or list (for `multiple`).
486
- */
487
- async select(index) {
488
- const { _wa, _doc } = this;
489
- const indices = Array.isArray(index) ? index : [index];
490
- const opts = this._poll?.options ?? [];
491
- const selected_options = indices
492
- .filter((i) => i >= 0 && i < opts.length)
493
- .map((i) => sha256(Buffer.from(opts[i].optionName ?? '')));
494
- const poll_enc_key = _doc.raw.message?.messageContextInfo?.messageSecret;
495
- if (!poll_enc_key || !_wa._socket || selected_options.length === 0) {
496
- return false;
497
- }
498
- const voter_jid = jidNormalizedUser(_wa._socket.user?.id ?? '');
499
- const poll_creator_jid = getKeyAuthor(_doc.raw.key, _wa._socket.user?.id);
500
- const poll_msg_id = this.id;
501
- // Derivar clave y encriptar el voto (mismo algoritmo que baileys.decryptPollVote)
502
- const sign = Buffer.concat([
503
- Buffer.from(poll_msg_id),
504
- Buffer.from(poll_creator_jid),
505
- Buffer.from(voter_jid),
506
- Buffer.from('Poll Vote'),
507
- new Uint8Array([1]),
508
- ]);
509
- const key0 = hmacSign(Buffer.from(poll_enc_key), new Uint8Array(32), 'sha256');
510
- const enc_key = hmacSign(sign, key0, 'sha256');
511
- const payload = proto.Message.PollVoteMessage.encode({
512
- selectedOptions: selected_options,
513
- }).finish();
514
- const aad = Buffer.from(`${poll_msg_id}\x00${voter_jid}`);
515
- const enc_iv = randomBytes(12);
516
- const enc_payload = aesEncryptGCM(payload, enc_key, enc_iv, aad);
517
- const msg_id = generateMessageID();
518
- await _wa._socket.relayMessage(_doc.cid, {
519
- pollUpdateMessage: {
520
- pollCreationMessageKey: _doc.raw.key,
521
- vote: { encPayload: enc_payload, encIv: enc_iv },
522
- senderTimestampMs: Date.now(),
523
- },
524
- }, { messageId: msg_id });
525
- return true;
526
- }
527
- }
528
- /**
529
- * Factoría que enlaza los statics a `wa` y expone las subclases.
530
- * Factory binding statics to `wa` and exposing subclasses.
531
- */
532
- export function message(wa) {
533
- async function build_instance(doc) {
534
- const opts = { wa, doc };
535
- if (doc.type === 'text') {
536
- return new Text(opts);
537
- }
538
- if (doc.type === 'image') {
539
- return new Image(opts);
540
- }
541
- if (doc.type === 'video') {
542
- return new Video(opts);
543
- }
544
- if (doc.type === 'audio') {
545
- return new Audio(opts);
546
- }
547
- if (doc.type === 'location') {
548
- return new Gps(opts);
549
- }
550
- if (doc.type === 'poll') {
551
- return new Poll(opts);
552
- }
553
- return new Message(opts);
554
- }
555
- async function send(cid, content, binary, reply_to) {
556
- let result = null;
557
- const jid = await wa._resolve_jid(cid);
558
- if (jid && wa._socket) {
559
- let quoted;
560
- if (reply_to) {
561
- const ref_doc = deserialize(await wa.engine.get(`/chat/${jid}/message/${reply_to}`));
562
- if (ref_doc) {
563
- quoted = ref_doc.raw;
564
- }
565
- }
566
- const raw = await wa._socket.sendMessage(jid, {
567
- ...content,
568
- ...(quoted ? { quoted } : {}),
569
- });
570
- const sent_id = raw?.key?.id;
571
- if (raw && sent_id) {
572
- const doc = build_message_doc(raw, wa._socket?.user?.id);
573
- await wa.engine.set(`/chat/${jid}/message/${sent_id}`, serialize(doc));
574
- if (binary) {
575
- await wa.engine.set(`/chat/${jid}/message/${sent_id}/content`, serialize({ data: binary.toString('base64') }));
576
- }
577
- result = await build_instance(doc);
578
- }
579
- }
580
- return result;
581
- }
582
- const api = {
583
- // Clases expuestas para instanceof
584
- Text,
585
- Image,
586
- Video,
587
- Audio,
588
- Gps,
589
- Poll,
590
- // Helpers internos (usados por orquestador WhatsApp)
591
- build_message_doc,
592
- build_instance,
593
- /** Obtiene un mensaje por CID/MID. */
594
- async get(cid, mid) {
595
- const jid = await wa._resolve_jid(cid);
596
- if (!jid) {
597
- return null;
598
- }
599
- const doc = deserialize(await wa.engine.get(`/chat/${jid}/message/${mid}`));
600
- return doc ? build_instance(doc) : null;
601
- },
602
- /** Pagina mensajes de un chat. */
603
- async list(cid, offset = 0, limit = 50) {
604
- const jid = await wa._resolve_jid(cid);
605
- const result = [];
606
- if (jid) {
607
- for (const raw of await wa.engine.list(`/chat/${jid}/message`, offset, limit)) {
608
- const doc = deserialize(raw);
609
- if (doc) {
610
- result.push(await build_instance(doc));
611
- }
612
- }
613
- }
614
- return result;
615
- },
616
- /** Cuenta mensajes de un chat. */
617
- async count(cid) {
618
- const jid = await wa._resolve_jid(cid);
619
- return jid ? wa.engine.count(`/chat/${jid}/message`) : 0;
620
- },
621
- async text(cid, caption, opts = {}) {
622
- return send(cid, { text: caption }, undefined, opts.mid);
623
- },
624
- async image(cid, buf, opts = {}) {
625
- return send(cid, { image: buf, caption: opts.caption }, buf, opts.mid);
626
- },
627
- async video(cid, buf, opts = {}) {
628
- return send(cid, { video: buf, caption: opts.caption }, buf, opts.mid);
629
- },
630
- async audio(cid, buf, opts = {}) {
631
- return send(cid, { audio: buf, ptt: opts.ptt ?? true }, buf, opts.mid);
632
- },
633
- async location(cid, loc, opts = {}) {
634
- return send(cid, { location: { degreesLatitude: loc.lat, degreesLongitude: loc.lng } }, undefined, opts.mid);
635
- },
636
- async poll(cid, p, opts = {}) {
637
- return send(cid, { poll: { name: p.content, values: p.options.map((o) => o.content), selectableCount: 1 } }, undefined, opts.mid);
638
- },
639
- async edit(cid, mid, text) {
640
- const m = await api.get(cid, mid);
641
- return m ? m.edit(text) : false;
642
- },
643
- async delete(cid, mid, all = true) {
644
- const m = await api.get(cid, mid);
645
- return m ? m.delete(all) : false;
646
- },
647
- async react(cid, mid, emoji) {
648
- const m = await api.get(cid, mid);
649
- return m ? m.react(emoji) : false;
650
- },
651
- async forward(cid, mid, target) {
652
- const m = await api.get(cid, mid);
653
- return m ? m.forward(target) : false;
654
- },
655
- async seen(cid, mid) {
656
- const m = await api.get(cid, mid);
657
- return m ? m.seen() : false;
658
- },
659
- async star(cid, mid, value) {
660
- const m = await api.get(cid, mid);
661
- return m ? m.star(value) : false;
662
- },
663
- watch(cid, mid, handler) {
664
- return wa.on('message:updated', (updated) => {
665
- if (updated.cid === cid && updated.id === mid) {
666
- handler(updated);
667
- }
668
- });
669
- },
670
- };
671
- return api;
672
- }
673
- //# sourceMappingURL=index.js.map