@arcaelas/whatsapp 6.1.3 → 7.0.0
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/README.md +19 -15
- package/build/cjs/index.d.ts +9 -5
- package/build/cjs/index.js +8 -7
- package/build/cjs/lib/bot/decorator.d.ts +2 -9
- package/build/cjs/lib/bot/decorator.js +0 -1
- package/build/cjs/lib/bot/decorators.d.ts +48 -4
- package/build/cjs/lib/bot/decorators.js +2 -2
- package/build/cjs/lib/chat/index.d.ts +144 -152
- package/build/cjs/lib/chat/index.js +138 -209
- package/build/cjs/lib/contact/index.d.ts +114 -80
- package/build/cjs/lib/contact/index.js +187 -94
- package/build/cjs/lib/message/index.d.ts +400 -321
- package/build/cjs/lib/message/index.js +425 -913
- package/build/cjs/lib/status/index.d.ts +22 -33
- package/build/cjs/lib/status/index.js +52 -93
- package/build/cjs/lib/store/index.d.ts +16 -0
- package/build/cjs/lib/store/index.js +29 -3
- package/build/cjs/lib/whatsapp/index.d.ts +44 -212
- package/build/cjs/lib/whatsapp/index.js +473 -1067
- package/build/esm/index.d.ts +9 -5
- package/build/esm/index.js +6 -4
- package/build/esm/lib/bot/decorator.d.ts +2 -9
- package/build/esm/lib/bot/decorator.js +1 -1
- package/build/esm/lib/bot/decorators.d.ts +48 -4
- package/build/esm/lib/bot/decorators.js +2 -2
- package/build/esm/lib/chat/index.d.ts +144 -152
- package/build/esm/lib/chat/index.js +139 -209
- package/build/esm/lib/contact/index.d.ts +114 -80
- package/build/esm/lib/contact/index.js +186 -94
- package/build/esm/lib/message/index.d.ts +400 -321
- package/build/esm/lib/message/index.js +422 -913
- package/build/esm/lib/status/index.d.ts +22 -33
- package/build/esm/lib/status/index.js +49 -93
- package/build/esm/lib/store/index.d.ts +16 -0
- package/build/esm/lib/store/index.js +25 -0
- package/build/esm/lib/whatsapp/index.d.ts +44 -212
- package/build/esm/lib/whatsapp/index.js +476 -1069
- package/package.json +1 -1
- package/build/cjs/lib/internal.d.ts +0 -40
- package/build/cjs/lib/internal.js +0 -38
- package/build/esm/lib/internal.d.ts +0 -40
- package/build/esm/lib/internal.js +0 -34
|
@@ -1,895 +1,440 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* @file message/index.ts
|
|
4
|
-
* @description Entidad Message — clase base con getters puros y subclases por tipo
|
|
5
|
-
* (
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `message(wa, raw)` evaluates the type and returns the right instance.
|
|
4
|
+
* @description Entidad Message — clase base con getters puros y subclases por tipo;
|
|
5
|
+
* `message(init)` devuelve la clase ligada a la sesión con los envíos y lecturas.
|
|
6
|
+
* Message entity — pure-getter base class with per-type subclasses; `message(init)`
|
|
7
|
+
* returns the session-bound class with sends and reads.
|
|
9
8
|
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
10
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.Event = exports.VCard = exports.Poll = exports.Location = exports.Document = exports.Sticker = exports.Audio = exports.Video = exports.Image = exports.Text =
|
|
13
|
+
exports.Event = exports.VCard = exports.Poll = exports.Location = exports.Document = exports.Sticker = exports.Audio = exports.Video = exports.Image = exports.Text = void 0;
|
|
12
14
|
exports.message = message;
|
|
13
15
|
const baileys_1 = require("baileys");
|
|
14
16
|
const node_crypto_1 = require("node:crypto");
|
|
15
17
|
const node_stream_1 = require("node:stream");
|
|
16
|
-
const
|
|
17
|
-
const chat_1 = require("../../lib/chat");
|
|
18
|
+
const chat_1 = __importDefault(require("../../lib/chat"));
|
|
18
19
|
const store_1 = require("../../lib/store");
|
|
19
20
|
/** Estados legibles indexados por el status numérico de baileys. / Readable states indexed by the baileys numeric status. */
|
|
20
21
|
const STATUS = ['error', 'pending', 'sent', 'delivered', 'read', 'played'];
|
|
22
|
+
/** Desenvuelve los wrappers de contenido (view-once, documento con caption). / Unwraps content wrappers (view-once, captioned document). */
|
|
23
|
+
const unwrap = (msg) => msg.viewOnceMessage?.message ?? msg.viewOnceMessageV2?.message ?? msg.viewOnceMessageV2Extension?.message ?? msg.documentWithCaptionMessage?.message ?? msg;
|
|
24
|
+
/** Bytes del proto (Uint8Array en runtime, base64 tras el engine) como Buffer. / Proto bytes (runtime Uint8Array, post-engine base64) as a Buffer. */
|
|
25
|
+
const to_buffer = (value) => value instanceof Uint8Array && value.length ? Buffer.from(value) : typeof value === 'string' && value ? Buffer.from(value, 'base64') : null;
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
27
|
+
* Envío base: resuelve el destino, cita si hay `mid`, marca view-once, persiste el documento
|
|
28
|
+
* con su binario y retorna la instancia del tipo correcto. La cita viaja en las opciones del
|
|
29
|
+
* socket: dentro del contenido baileys la ignora.
|
|
30
|
+
* Base send: resolves the target, quotes when `mid` is given, flags view-once, persists the
|
|
31
|
+
* document with its binary and returns the right-type instance. The quote travels in the
|
|
32
|
+
* socket options: inside the content baileys ignores it.
|
|
26
33
|
*/
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
const send = async (init, cid, content, binary, extra = {}, overrides) => {
|
|
35
|
+
const jid = await (0, store_1.jid_of)(init.engine, cid, init.socket);
|
|
36
|
+
if (!jid)
|
|
37
|
+
return null;
|
|
38
|
+
const quoted = extra.mid ? (0, store_1.deserialize)(await init.engine.get(`/chat/${jid}/message/${extra.mid}`))?.raw : undefined;
|
|
39
|
+
const raw = await init.socket.sendMessage(jid, { ...content, ...(extra.once && { viewOnce: true }) }, { ...(quoted && { quoted }) });
|
|
40
|
+
if (!raw?.key?.id)
|
|
41
|
+
return null;
|
|
42
|
+
const sent = new Message(init, raw);
|
|
43
|
+
Object.assign(sent._raw, overrides);
|
|
44
|
+
await init.engine.set(`/chat/${jid}/message/${raw.key.id}`, (0, store_1.serialize)(sent._raw), sent._raw.created_at);
|
|
45
|
+
const path = `/chat/${jid}/message/${raw.key.id}/content`;
|
|
46
|
+
if (binary)
|
|
47
|
+
await (init.engine.set_buffer?.(path, binary) ?? init.engine.set(path, (0, store_1.serialize)({ data: binary.toString('base64') })));
|
|
48
|
+
return sent;
|
|
30
49
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
pollCreationMessage: 'poll',
|
|
41
|
-
pollCreationMessageV2: 'poll',
|
|
42
|
-
pollCreationMessageV3: 'poll',
|
|
43
|
-
documentMessage: 'document',
|
|
44
|
-
documentWithCaptionMessage: 'document',
|
|
45
|
-
contactMessage: 'vcard',
|
|
46
|
-
contactsArrayMessage: 'vcard',
|
|
47
|
-
eventMessage: 'event',
|
|
50
|
+
/** Contenido proto de una encuesta. / Poll proto content. */
|
|
51
|
+
const poll_of = (input, multiple) => ({ poll: { name: input.content, values: input.options.map((option) => option.content), selectableCount: multiple ? 0 : 1 } });
|
|
52
|
+
/** Contenido y binario de las tarjetas de contacto. / Contact cards content and binary. */
|
|
53
|
+
const vcards_of = (contacts) => {
|
|
54
|
+
const cards = contacts.map((entry) => ({
|
|
55
|
+
displayName: entry.name,
|
|
56
|
+
vcard: `BEGIN:VCARD\nVERSION:3.0\nFN:${entry.name}\nTEL;type=CELL;waid=${entry.phone.replace(/\D+/g, '')}:${entry.phone}\nEND:VCARD`,
|
|
57
|
+
}));
|
|
58
|
+
return { content: { contacts: { contacts: cards } }, binary: Buffer.from(cards.map((entry) => entry.vcard).join('\n'), 'utf-8') };
|
|
48
59
|
};
|
|
60
|
+
/** Contenido y binario del evento. / Event content and binary. */
|
|
61
|
+
const event_of = (data) => ({
|
|
62
|
+
content: {
|
|
63
|
+
event: {
|
|
64
|
+
name: data.name,
|
|
65
|
+
description: data.caption,
|
|
66
|
+
startDate: data.start,
|
|
67
|
+
endDate: data.end,
|
|
68
|
+
location: data.place ? { degreesLatitude: data.place.lat, degreesLongitude: data.place.lng } : undefined,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
binary: Buffer.from(JSON.stringify({ name: data.name, caption: data.caption, start: data.start.getTime(), end: data.end?.getTime() ?? null }), 'utf-8'),
|
|
72
|
+
});
|
|
49
73
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return (msg.viewOnceMessage?.message ??
|
|
55
|
-
msg.viewOnceMessageV2?.message ??
|
|
56
|
-
msg.viewOnceMessageV2Extension?.message ??
|
|
57
|
-
msg.documentWithCaptionMessage?.message ??
|
|
58
|
-
msg);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Convierte un número o Long del proto a number plano.
|
|
62
|
-
* Converts a proto number or Long into a plain number.
|
|
63
|
-
*/
|
|
64
|
-
function to_number(value) {
|
|
65
|
-
return Number(value?.toString() ?? 0);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Convierte los bytes del proto (Uint8Array runtime o base64 post-engine) a Buffer.
|
|
69
|
-
* Converts proto bytes (runtime Uint8Array or post-engine base64) into a Buffer.
|
|
70
|
-
*/
|
|
71
|
-
function to_buffer(value) {
|
|
72
|
-
if (value instanceof Uint8Array && value.length > 0)
|
|
73
|
-
return Buffer.from(value);
|
|
74
|
-
if (typeof value === 'string' && value.length > 0)
|
|
75
|
-
return Buffer.from(value, 'base64');
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Envío base: resuelve el destino, cita si hay `mid`, marca view-once, persiste el doc
|
|
80
|
-
* (con su binario cuando aplica) y retorna la instancia del mensaje enviado.
|
|
81
|
-
* Base send: resolves the target, quotes when `mid` is given, flags view-once, persists
|
|
82
|
-
* the doc (with its binary when it applies) and returns the sent message instance.
|
|
83
|
-
*/
|
|
84
|
-
async function send(wa, cid, content, binary, extra = {}, doc_overrides) {
|
|
85
|
-
let result = null;
|
|
86
|
-
const jid = await (0, internal_1.internals)(wa).resolve_jid(cid);
|
|
87
|
-
const socket = (0, internal_1.internals)(wa).socket;
|
|
88
|
-
if (jid && socket) {
|
|
89
|
-
const quoted = extra.mid
|
|
90
|
-
? ((0, store_1.deserialize)(await wa.engine.get(`/chat/${jid}/message/${extra.mid}`))?.raw ?? undefined)
|
|
91
|
-
: undefined;
|
|
92
|
-
// La cita viaja en las opciones del socket, no en el contenido: dentro del contenido
|
|
93
|
-
// baileys la ignora y el mensaje sale sin `contextInfo`.
|
|
94
|
-
// The quote travels in the socket options, not in the content: inside the content
|
|
95
|
-
// baileys ignores it and the message goes out without `contextInfo`.
|
|
96
|
-
const raw = await socket.sendMessage(jid, { ...content, ...(extra.once && { viewOnce: true }) }, { ...(quoted && { quoted }) });
|
|
97
|
-
const sent_id = raw?.key?.id;
|
|
98
|
-
if (raw && sent_id) {
|
|
99
|
-
const instance = message(wa, raw);
|
|
100
|
-
if (doc_overrides) {
|
|
101
|
-
Object.assign(instance._raw, doc_overrides);
|
|
102
|
-
}
|
|
103
|
-
await wa.engine.set(`/chat/${jid}/message/${sent_id}`, (0, store_1.serialize)(instance._raw), instance._raw.created_at);
|
|
104
|
-
if (binary) {
|
|
105
|
-
await write_content(wa, `/chat/${jid}/message/${sent_id}/content`, binary);
|
|
106
|
-
}
|
|
107
|
-
result = instance;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Binario persistido de un documento: primero el crudo del engine y, si el driver no soporta
|
|
114
|
-
* binarios o el dato viene de una sesión anterior, el documento JSON con base64.
|
|
115
|
-
* A document's persisted binary: the engine's raw one first and, when the driver lacks binary
|
|
116
|
-
* support or the data comes from an older session, the base64 JSON document.
|
|
117
|
-
*
|
|
118
|
-
* @param wa - Cliente dueño / Owner client
|
|
119
|
-
* @param path - Ruta del contenido / Content path
|
|
120
|
-
* @returns Binario o null / Binary or null
|
|
121
|
-
*/
|
|
122
|
-
async function read_content(wa, path) {
|
|
123
|
-
const raw = await wa.engine.get_buffer?.(path);
|
|
124
|
-
if (raw?.length) {
|
|
125
|
-
return raw;
|
|
126
|
-
}
|
|
127
|
-
const legacy = (0, store_1.deserialize)(await wa.engine.get(path));
|
|
128
|
-
return legacy?.data ? Buffer.from(legacy.data, 'base64') : null;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Persiste el binario de un documento: crudo cuando el driver lo soporta, JSON con base64
|
|
132
|
-
* en caso contrario.
|
|
133
|
-
* Persists a document's binary: raw when the driver supports it, base64 JSON otherwise.
|
|
134
|
-
*
|
|
135
|
-
* @param wa - Cliente dueño / Owner client
|
|
136
|
-
* @param path - Ruta del contenido / Content path
|
|
137
|
-
* @param data - Binario a guardar / Binary to store
|
|
138
|
-
*/
|
|
139
|
-
async function write_content(wa, path, data) {
|
|
140
|
-
if (wa.engine.set_buffer) {
|
|
141
|
-
await wa.engine.set_buffer(path, data);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
await wa.engine.set(path, (0, store_1.serialize)({ data: data.toString('base64') }));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Stream del binario del mensaje: cache del engine o descarga de baileys.
|
|
149
|
-
* Message binary stream: engine cache or baileys download.
|
|
150
|
-
*/
|
|
151
|
-
async function media_stream(wa, doc) {
|
|
152
|
-
const cached = await read_content(wa, `/chat/${doc.cid}/message/${doc.id}/content`);
|
|
153
|
-
if (cached) {
|
|
154
|
-
return node_stream_1.Readable.from(cached);
|
|
155
|
-
}
|
|
156
|
-
const socket = (0, internal_1.internals)(wa).socket;
|
|
157
|
-
if (socket) {
|
|
158
|
-
try {
|
|
159
|
-
return (await (0, baileys_1.downloadMediaMessage)(doc.raw, 'stream', {}));
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
/* media may be expired */
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return node_stream_1.Readable.from(Buffer.alloc(0));
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Acumula un Readable en Buffer.
|
|
169
|
-
* Drains a Readable into a Buffer.
|
|
170
|
-
*/
|
|
171
|
-
async function drain(readable) {
|
|
172
|
-
const chunks = [];
|
|
173
|
-
for await (const chunk of readable) {
|
|
174
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
175
|
-
}
|
|
176
|
-
return Buffer.concat(chunks);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Clase base del mensaje: recibe el cliente y el raw, deriva el estado con getters y
|
|
180
|
-
* opera contra WhatsApp con sus métodos. Los estáticos reciben el cliente como primer
|
|
181
|
-
* argumento (`Message.text(wa, cid, …)`).
|
|
182
|
-
* Base message class: receives the client and the raw, derives state via getters and
|
|
183
|
-
* operates against WhatsApp with its methods. Statics take the client as their first
|
|
184
|
-
* argument (`Message.text(wa, cid, …)`).
|
|
74
|
+
* Mensaje: recibe la sesión y el documento, deriva el estado con getters y opera contra
|
|
75
|
+
* WhatsApp con sus métodos. Los de respuesta citan automáticamente este mensaje.
|
|
76
|
+
* Message: receives the session and the document, derives state via getters and operates
|
|
77
|
+
* against WhatsApp with its methods. Reply methods quote this message automatically.
|
|
185
78
|
*/
|
|
186
79
|
class Message {
|
|
187
80
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
81
|
+
* Recibe la sesión y el documento persistido, o el crudo de baileys: en ese caso el
|
|
82
|
+
* documento se deriva aquí y se despacha la subclase del tipo — `new Message(init, raw)`
|
|
83
|
+
* de una encuesta devuelve un `Poll`.
|
|
84
|
+
* Receives the session and the persisted document, or the baileys raw: in that case the
|
|
85
|
+
* document is derived here and the per-type subclass is dispatched — `new Message(init,
|
|
86
|
+
* raw)` of a poll returns a `Poll`.
|
|
194
87
|
*/
|
|
195
|
-
constructor(
|
|
196
|
-
|
|
197
|
-
|
|
88
|
+
constructor(init, raw) {
|
|
89
|
+
let doc = raw;
|
|
90
|
+
if ('key' in raw) {
|
|
91
|
+
const key = raw.key ?? {};
|
|
92
|
+
const unwrapped = unwrap(raw.message ?? {});
|
|
93
|
+
const kind = (0, baileys_1.getContentType)(unwrapped);
|
|
94
|
+
const type = {
|
|
95
|
+
conversation: 'text', extendedTextMessage: 'text', imageMessage: 'image', videoMessage: 'video',
|
|
96
|
+
audioMessage: 'audio', stickerMessage: 'sticker', locationMessage: 'location', liveLocationMessage: 'location',
|
|
97
|
+
pollCreationMessage: 'poll', pollCreationMessageV2: 'poll', pollCreationMessageV3: 'poll',
|
|
98
|
+
documentMessage: 'document', documentWithCaptionMessage: 'document', contactMessage: 'vcard',
|
|
99
|
+
contactsArrayMessage: 'vcard', eventMessage: 'event',
|
|
100
|
+
}[kind ?? ''] ?? 'text';
|
|
101
|
+
const content = unwrapped[kind];
|
|
102
|
+
const context = content?.contextInfo;
|
|
103
|
+
const ephemeral = raw.ephemeralDuration ?? context?.expiration;
|
|
104
|
+
doc = {
|
|
105
|
+
id: key.id ?? '',
|
|
106
|
+
cid: key.remoteJidAlt ?? key.remoteJid ?? '',
|
|
107
|
+
mid: context?.stanzaId ?? null,
|
|
108
|
+
me: key.fromMe ?? false,
|
|
109
|
+
type,
|
|
110
|
+
author: key.fromMe && init.socket.user?.id
|
|
111
|
+
? (0, baileys_1.jidNormalizedUser)(init.socket.user.id)
|
|
112
|
+
: key.participant || key.remoteJidAlt || key.remoteJid || '',
|
|
113
|
+
status: raw.status ?? 1,
|
|
114
|
+
starred: raw.starred ?? false,
|
|
115
|
+
forwarded: context?.isForwarded ?? false,
|
|
116
|
+
created_at: (Number(raw.messageTimestamp) || Math.floor(Date.now() / 1_000)) * 1_000,
|
|
117
|
+
deleted_at: raw.ephemeralStartTimestamp != null && ephemeral != null ? (Number(raw.ephemeralStartTimestamp) + ephemeral) * 1_000 : null,
|
|
118
|
+
mime: typeof content === 'object' && type !== 'text' ? (content?.mimetype ?? 'application/octet-stream') : 'text/plain',
|
|
119
|
+
caption: typeof content === 'string' ? content
|
|
120
|
+
: type === 'event' ? (content?.description ?? '')
|
|
121
|
+
: (content?.caption ?? content?.text ?? content?.name ?? content?.displayName ?? ''),
|
|
122
|
+
edited: false,
|
|
123
|
+
raw,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (new.target === Message) {
|
|
127
|
+
const kinds = { text: Text, image: Image, video: Video, audio: Audio, sticker: Sticker, document: Document, location: Location, poll: Poll, vcard: VCard, event: Event };
|
|
128
|
+
return new kinds[doc.type](init, doc);
|
|
129
|
+
}
|
|
130
|
+
this._init = init;
|
|
131
|
+
this._raw = doc;
|
|
198
132
|
}
|
|
199
133
|
/** Identificador del mensaje. / Message identifier. */
|
|
200
|
-
get id() {
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
/** Identificador del chat del mensaje. / Message chat identifier. */
|
|
204
|
-
get cid() {
|
|
205
|
-
return this._raw.cid;
|
|
206
|
-
}
|
|
134
|
+
get id() { return this._raw.id; }
|
|
135
|
+
/** Identificador del chat. / Chat identifier. */
|
|
136
|
+
get cid() { return this._raw.cid; }
|
|
207
137
|
/** Identificador del mensaje citado, o null. / Quoted message identifier, or null. */
|
|
208
|
-
get mid() {
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
/** JID del autor, para acceso síncrono. / Author JID, for sync access. */
|
|
212
|
-
get from() {
|
|
213
|
-
return this._raw.author;
|
|
214
|
-
}
|
|
138
|
+
get mid() { return this._raw.mid; }
|
|
139
|
+
/** JID del autor. / Author JID. */
|
|
140
|
+
get from() { return this._raw.author; }
|
|
215
141
|
/** true si soy el autor. / true when I am the author. */
|
|
216
|
-
get me() {
|
|
217
|
-
return this._raw.me;
|
|
218
|
-
}
|
|
142
|
+
get me() { return this._raw.me; }
|
|
219
143
|
/** Tipo del mensaje. / Message type. */
|
|
220
|
-
get type() {
|
|
221
|
-
return this._raw.type;
|
|
222
|
-
}
|
|
223
|
-
/** MIME: text/plain en texto, text/json en poll/location/vcard/event, real en media. / MIME: text/plain for text, text/json for poll/location/vcard/event, actual for media. */
|
|
224
|
-
get mime() {
|
|
225
|
-
const { type } = this._raw;
|
|
226
|
-
if (type === 'text')
|
|
227
|
-
return 'text/plain';
|
|
228
|
-
if (type === 'poll' || type === 'location' || type === 'vcard' || type === 'event')
|
|
229
|
-
return 'text/json';
|
|
230
|
-
return this._raw.mime;
|
|
231
|
-
}
|
|
144
|
+
get type() { return this._raw.type; }
|
|
232
145
|
/** Texto del mensaje o caption del media. / Message text or media caption. */
|
|
233
|
-
get caption() {
|
|
234
|
-
return this._raw.caption;
|
|
235
|
-
}
|
|
146
|
+
get caption() { return this._raw.caption; }
|
|
236
147
|
/** Estado legible del mensaje. / Readable message state. */
|
|
237
|
-
get status() {
|
|
238
|
-
return STATUS[this._raw.status] ?? 'pending';
|
|
239
|
-
}
|
|
148
|
+
get status() { return STATUS[this._raw.status] ?? 'pending'; }
|
|
240
149
|
/** true si el mensaje fue visto. / true when the message was seen. */
|
|
241
|
-
get read() {
|
|
242
|
-
|
|
150
|
+
get read() { return this._raw.status >= baileys_1.proto.WebMessageInfo.Status.READ; }
|
|
151
|
+
/** true si está destacado. / true when starred. */
|
|
152
|
+
get starred() { return this._raw.starred; }
|
|
153
|
+
/** true si fue reenviado. / true when forwarded. */
|
|
154
|
+
get forwarded() { return this._raw.forwarded; }
|
|
155
|
+
/** true si fue editado. / true when edited. */
|
|
156
|
+
get edited() { return this._raw.edited; }
|
|
157
|
+
/** Fecha de creación en ISO UTC. / Creation date as ISO UTC. */
|
|
158
|
+
get created_at() { return new Date(this._raw.created_at).toISOString(); }
|
|
159
|
+
/** Vencimiento del mensaje temporal en ISO UTC, o null. / Ephemeral expiration as ISO UTC, or null. */
|
|
160
|
+
get expires_at() { return this._raw.deleted_at != null ? new Date(this._raw.deleted_at).toISOString() : null; }
|
|
161
|
+
/** MIME: text/plain en texto, text/json en poll/location/vcard/event, real en media. / MIME: text/plain for text, text/json for poll/location/vcard/event, actual for media. */
|
|
162
|
+
get mime() {
|
|
163
|
+
const { type } = this._raw;
|
|
164
|
+
return type === 'text' ? 'text/plain' : ['poll', 'location', 'vcard', 'event'].includes(type) ? 'text/json' : this._raw.mime;
|
|
243
165
|
}
|
|
244
|
-
/** Motivo del rechazo cuando `status` es `error` (`restricted`, `invalid-session`, o el código crudo); null
|
|
166
|
+
/** Motivo del rechazo cuando `status` es `error` (`restricted`, `invalid-session`, o el código crudo); null si no. / Rejection reason when `status` is `error` (`restricted`, `invalid-session`, or the raw code); null otherwise. */
|
|
245
167
|
get reason() {
|
|
246
168
|
const code = this._raw.raw.messageStubParameters?.[0];
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
169
|
+
return this._raw.status === baileys_1.proto.WebMessageInfo.Status.ERROR && code
|
|
170
|
+
? { '463': 'restricted', '479': 'invalid-session' }[code] ?? code
|
|
171
|
+
: null;
|
|
250
172
|
}
|
|
251
173
|
/** Nombre del negocio verificado que firma el mensaje, o null. / Verified business name signing the message, or null. */
|
|
252
|
-
get business() {
|
|
253
|
-
return this._raw.raw.verifiedBizName ?? null;
|
|
254
|
-
}
|
|
255
|
-
/** true si está destacado. / true when starred. */
|
|
256
|
-
get starred() {
|
|
257
|
-
return this._raw.starred;
|
|
258
|
-
}
|
|
259
|
-
/** true si fue reenviado. / true when forwarded. */
|
|
260
|
-
get forwarded() {
|
|
261
|
-
return this._raw.forwarded;
|
|
262
|
-
}
|
|
263
|
-
/** true si fue editado. / true when edited. */
|
|
264
|
-
get edited() {
|
|
265
|
-
return this._raw.edited;
|
|
266
|
-
}
|
|
174
|
+
get business() { return this._raw.raw.verifiedBizName ?? null; }
|
|
267
175
|
/** true si es de una sola lectura (view-once). / true when view-once. */
|
|
268
176
|
get once() {
|
|
269
177
|
const msg = this._raw.raw.message;
|
|
270
178
|
return Boolean(msg?.viewOnceMessage ?? msg?.viewOnceMessageV2 ?? msg?.viewOnceMessageV2Extension);
|
|
271
179
|
}
|
|
272
|
-
/**
|
|
273
|
-
get created_at() {
|
|
274
|
-
return new Date(this._raw.created_at).toISOString();
|
|
275
|
-
}
|
|
276
|
-
/** Vencimiento del mensaje temporal en ISO UTC, o null. / Ephemeral expiration as ISO UTC, or null. */
|
|
277
|
-
get expires_at() {
|
|
278
|
-
return this._raw.deleted_at != null ? new Date(this._raw.deleted_at).toISOString() : null;
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Contacto autor del mensaje, desde el engine (ficha mínima si no está persistido).
|
|
282
|
-
* Message author contact, from the engine (minimal card when not persisted).
|
|
283
|
-
*
|
|
284
|
-
* @returns Contacto / Contact
|
|
285
|
-
*/
|
|
180
|
+
/** Contacto autor, desde el engine (ficha mínima si no está persistido). / Author contact, from the engine (minimal card when not persisted). */
|
|
286
181
|
async author() {
|
|
287
|
-
|
|
288
|
-
return new this._wa.Contact(cached ?? { id: this._raw.author });
|
|
182
|
+
return new this._init.wa.Contact((0, store_1.deserialize)(await this._init.engine.get(`/contact/${this._raw.author}`)) ?? { id: this._raw.author });
|
|
289
183
|
}
|
|
290
|
-
/**
|
|
291
|
-
* Chat al que pertenece el mensaje.
|
|
292
|
-
* Chat the message belongs to.
|
|
293
|
-
*
|
|
294
|
-
* @returns Chat / Chat
|
|
295
|
-
*/
|
|
184
|
+
/** Chat al que pertenece el mensaje. / Chat the message belongs to. */
|
|
296
185
|
async chat() {
|
|
297
|
-
|
|
298
|
-
return new this._wa.Chat(cached ?? { id: this._raw.cid });
|
|
186
|
+
return new this._init.wa.Chat((0, store_1.deserialize)(await this._init.engine.get(`/chat/${this._raw.cid}`)) ?? { id: this._raw.cid });
|
|
299
187
|
}
|
|
300
|
-
/**
|
|
301
|
-
* Mensaje citado cuando hay `mid`, o null.
|
|
302
|
-
* Quoted message when `mid` exists, or null.
|
|
303
|
-
*
|
|
304
|
-
* @returns Mensaje citado o null / Quoted message or null
|
|
305
|
-
*/
|
|
188
|
+
/** Mensaje citado cuando hay `mid`, o null. / Quoted message when `mid` exists, or null. */
|
|
306
189
|
async message() {
|
|
307
|
-
|
|
190
|
+
const doc = this._raw.mid ? (0, store_1.deserialize)(await this._init.engine.get(`/chat/${this._raw.cid}/message/${this._raw.mid}`)) : null;
|
|
191
|
+
return doc ? new Message(this._init, doc) : null;
|
|
308
192
|
}
|
|
309
|
-
/**
|
|
310
|
-
* Contenido del mensaje: texto como su caption, media como binario, y
|
|
311
|
-
* poll/location/vcard/event como JSON.
|
|
312
|
-
* Message content: text as its caption, media as binary, and
|
|
313
|
-
* poll/location/vcard/event as JSON.
|
|
314
|
-
*
|
|
315
|
-
* @returns Buffer del contenido / Content buffer
|
|
316
|
-
*/
|
|
193
|
+
/** Contenido persistido: texto, JSON del tipo, o binario del media. / Persisted content: text, per-type JSON, or media binary. */
|
|
317
194
|
async content() {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
async stream() {
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Reacciones del mensaje agrupadas por emoji con su conteo.
|
|
331
|
-
* Message reactions grouped by emoji with their count.
|
|
332
|
-
*
|
|
333
|
-
* @returns Conteo por emoji / Per-emoji count
|
|
334
|
-
*/
|
|
195
|
+
const path = `/chat/${this._raw.cid}/message/${this._raw.id}/content`;
|
|
196
|
+
const cached = await this._init.engine.get_buffer?.(path);
|
|
197
|
+
if (cached?.length)
|
|
198
|
+
return cached;
|
|
199
|
+
const legacy = (0, store_1.deserialize)(await this._init.engine.get(path));
|
|
200
|
+
return legacy?.data ? Buffer.from(legacy.data, 'base64') : Buffer.alloc(0);
|
|
201
|
+
}
|
|
202
|
+
/** Stream del contenido. / Content stream. */
|
|
203
|
+
async stream() { return node_stream_1.Readable.from(await this.content()); }
|
|
204
|
+
/** Reacciones agrupadas por emoji con su conteo. / Reactions grouped by emoji with their count. */
|
|
335
205
|
async reactions() {
|
|
336
206
|
const counts = new Map();
|
|
337
|
-
for (const { emoji } of this._raw.reactions ?? [])
|
|
207
|
+
for (const { emoji } of this._raw.reactions ?? [])
|
|
338
208
|
counts.set(emoji, (counts.get(emoji) ?? 0) + 1);
|
|
339
|
-
}
|
|
340
209
|
return [...counts.entries()].map(([emoji, count]) => ({ emoji, count }));
|
|
341
210
|
}
|
|
342
211
|
/**
|
|
343
212
|
* Reacciona al mensaje; el emoji vacío retira la reacción.
|
|
344
|
-
* Reacts to the message; an empty emoji removes
|
|
213
|
+
* Reacts to the message; an empty emoji removes it.
|
|
345
214
|
*
|
|
346
215
|
* @param emoji - Emoji o '' / Emoji or ''
|
|
347
|
-
* @returns true si se envió / true when sent
|
|
348
216
|
*/
|
|
349
217
|
async react(emoji) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
react: {
|
|
356
|
-
text: emoji,
|
|
357
|
-
key: { remoteJid: cid, id, fromMe: me, ...(cid.endsWith('@g.us') && !me && { participant: author }) },
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
ok = true;
|
|
361
|
-
}
|
|
362
|
-
return ok;
|
|
218
|
+
const { cid, id, me, author } = this._raw;
|
|
219
|
+
await this._init.socket.sendMessage(cid, {
|
|
220
|
+
react: { text: emoji, key: { remoteJid: cid, id, fromMe: me, ...(cid.endsWith('@g.us') && !me && { participant: author }) } },
|
|
221
|
+
});
|
|
222
|
+
return true;
|
|
363
223
|
}
|
|
364
224
|
/**
|
|
365
|
-
* Destaca o quita el destacado
|
|
225
|
+
* Destaca o quita el destacado.
|
|
366
226
|
* Stars or unstars the message.
|
|
367
227
|
*
|
|
368
228
|
* @param value - true destaca / true stars
|
|
369
|
-
* @returns true si se envió / true when sent
|
|
370
229
|
*/
|
|
371
230
|
async star(value) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
doc.starred = value;
|
|
378
|
-
await this._wa.engine.set(`/chat/${doc.cid}/message/${doc.id}`, (0, store_1.serialize)(doc), doc.created_at);
|
|
379
|
-
ok = true;
|
|
380
|
-
}
|
|
381
|
-
return ok;
|
|
231
|
+
const doc = this._raw;
|
|
232
|
+
await this._init.socket.chatModify({ star: { messages: [{ id: doc.id, fromMe: doc.me }], star: value } }, doc.cid);
|
|
233
|
+
doc.starred = value;
|
|
234
|
+
await this._init.engine.set(`/chat/${doc.cid}/message/${doc.id}`, (0, store_1.serialize)(doc), doc.created_at);
|
|
235
|
+
return true;
|
|
382
236
|
}
|
|
383
|
-
/**
|
|
384
|
-
* Marca el mensaje como leído.
|
|
385
|
-
* Marks the message as read.
|
|
386
|
-
*
|
|
387
|
-
* @returns true si se envió / true when sent
|
|
388
|
-
*/
|
|
237
|
+
/** Marca el mensaje como leído. / Marks the message as read. */
|
|
389
238
|
async seen() {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const { cid, id, author } = this._raw;
|
|
394
|
-
await socket.readMessages([
|
|
395
|
-
{ remoteJid: cid, id, participant: cid.endsWith('@g.us') ? author : undefined },
|
|
396
|
-
]);
|
|
397
|
-
ok = true;
|
|
398
|
-
}
|
|
399
|
-
return ok;
|
|
239
|
+
const { cid, id, author } = this._raw;
|
|
240
|
+
await this._init.socket.readMessages([{ remoteJid: cid, id, participant: cid.endsWith('@g.us') ? author : undefined }]);
|
|
241
|
+
return true;
|
|
400
242
|
}
|
|
401
243
|
/**
|
|
402
244
|
* Edita el caption del mensaje propio (texto, imagen o video).
|
|
403
245
|
* Edits the own message caption (text, image or video).
|
|
404
246
|
*
|
|
405
247
|
* @param caption - Texto nuevo / New text
|
|
406
|
-
* @returns
|
|
248
|
+
* @returns false si el mensaje no es propio o su tipo no se puede editar / false when not own or its type cannot be edited
|
|
407
249
|
*/
|
|
408
250
|
async edit(caption) {
|
|
409
251
|
const doc = this._raw;
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
protocolMessage: {
|
|
430
|
-
key: { remoteJid: doc.cid, id: doc.id, fromMe: true },
|
|
431
|
-
type: baileys_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
432
|
-
editedMessage: edited,
|
|
433
|
-
timestampMs: Date.now(),
|
|
434
|
-
},
|
|
435
|
-
}, { messageId: (0, baileys_1.generateMessageID)() });
|
|
436
|
-
doc.raw.message = { ...doc.raw.message, ...edited };
|
|
437
|
-
ok = true;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
if (ok) {
|
|
441
|
-
doc.caption = caption;
|
|
442
|
-
doc.edited = true;
|
|
443
|
-
await this._wa.engine.set(`/chat/${doc.cid}/message/${doc.id}`, (0, store_1.serialize)(doc), doc.created_at);
|
|
444
|
-
}
|
|
252
|
+
const media_key = doc.type === 'image' ? 'imageMessage' : doc.type === 'video' ? 'videoMessage' : null;
|
|
253
|
+
const media = media_key ? unwrap(doc.raw.message ?? {})[media_key] : null;
|
|
254
|
+
if (!doc.me || (doc.type !== 'text' && !media))
|
|
255
|
+
return false;
|
|
256
|
+
if (doc.type === 'text') {
|
|
257
|
+
await this._init.socket.sendMessage(doc.cid, { text: caption, edit: { remoteJid: doc.cid, id: doc.id, fromMe: true } });
|
|
258
|
+
doc.raw.message = (0, baileys_1.getContentType)(doc.raw.message ?? {}) === 'conversation' ? { conversation: caption } : { extendedTextMessage: { text: caption } };
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
const edited = { [media_key]: { ...media, caption } };
|
|
262
|
+
await this._init.socket.relayMessage(doc.cid, {
|
|
263
|
+
protocolMessage: {
|
|
264
|
+
key: { remoteJid: doc.cid, id: doc.id, fromMe: true },
|
|
265
|
+
type: baileys_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
266
|
+
editedMessage: edited,
|
|
267
|
+
timestampMs: Date.now(),
|
|
268
|
+
},
|
|
269
|
+
}, { messageId: (0, baileys_1.generateMessageID)() });
|
|
270
|
+
doc.raw.message = { ...doc.raw.message, ...edited };
|
|
445
271
|
}
|
|
446
|
-
|
|
272
|
+
doc.caption = caption;
|
|
273
|
+
doc.edited = true;
|
|
274
|
+
await this._init.engine.set(`/chat/${doc.cid}/message/${doc.id}`, (0, store_1.serialize)(doc), doc.created_at);
|
|
275
|
+
return true;
|
|
447
276
|
}
|
|
448
277
|
/**
|
|
449
278
|
* Reenvía el mensaje a otro chat.
|
|
450
279
|
* Forwards the message to another chat.
|
|
451
280
|
*
|
|
452
281
|
* @param target - CID, Chat o Contact destino / Target CID, Chat or Contact
|
|
453
|
-
* @returns
|
|
282
|
+
* @returns false si el destino es irresoluble o el contenido no admite reenvío / false when the target cannot be resolved or the content cannot be forwarded
|
|
454
283
|
*/
|
|
455
284
|
async forward(target) {
|
|
456
|
-
const
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
catch {
|
|
473
|
-
/* forward content may be unsupported */
|
|
474
|
-
}
|
|
475
|
-
}
|
|
285
|
+
const cid = typeof target === 'string' ? target : target instanceof chat_1.default ? target._raw.id : target.jid ?? target.lid ?? '';
|
|
286
|
+
const jid = cid ? await (0, store_1.jid_of)(this._init.engine, cid, this._init.socket) : null;
|
|
287
|
+
if (!jid || !this._raw.raw.message)
|
|
288
|
+
return false;
|
|
289
|
+
try {
|
|
290
|
+
const msg = (0, baileys_1.generateWAMessageFromContent)(jid, (0, baileys_1.generateForwardMessageContent)(this._raw.raw, false), { userJid: this._init.socket.user?.id ?? '' });
|
|
291
|
+
if (!msg.message || !msg.key?.id)
|
|
292
|
+
return false;
|
|
293
|
+
await this._init.socket.relayMessage(jid, msg.message, { messageId: msg.key.id });
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
/* contenido no reenviable / non-forwardable content */
|
|
298
|
+
return false;
|
|
476
299
|
}
|
|
477
|
-
return ok;
|
|
478
300
|
}
|
|
479
301
|
/**
|
|
480
302
|
* Elimina el mensaje: solo en mi dispositivo por defecto, para todos con `true`.
|
|
481
303
|
* Deletes the message: this device only by default, for everyone with `true`.
|
|
482
304
|
*
|
|
483
305
|
* @param all - true elimina para todos / true deletes for everyone
|
|
484
|
-
* @returns true si se eliminó / true when deleted
|
|
485
306
|
*/
|
|
486
307
|
async delete(all = false) {
|
|
487
308
|
const doc = this._raw;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
else {
|
|
495
|
-
await socket.chatModify({
|
|
496
|
-
deleteForMe: {
|
|
497
|
-
deleteMedia: false,
|
|
498
|
-
key: { remoteJid: doc.cid, id: doc.id, fromMe: doc.me },
|
|
499
|
-
timestamp: Date.now(),
|
|
500
|
-
},
|
|
501
|
-
}, doc.cid);
|
|
502
|
-
}
|
|
503
|
-
await this._wa.engine.unset(`/chat/${doc.cid}/message/${doc.id}`);
|
|
504
|
-
ok = true;
|
|
505
|
-
}
|
|
506
|
-
return ok;
|
|
309
|
+
if (all)
|
|
310
|
+
await this._init.socket.sendMessage(doc.cid, { delete: { remoteJid: doc.cid, id: doc.id, fromMe: doc.me } });
|
|
311
|
+
else
|
|
312
|
+
await this._init.socket.chatModify({ deleteForMe: { deleteMedia: false, key: { remoteJid: doc.cid, id: doc.id, fromMe: doc.me }, timestamp: Date.now() } }, doc.cid);
|
|
313
|
+
await this._init.engine.unset(`/chat/${doc.cid}/message/${doc.id}`);
|
|
314
|
+
return true;
|
|
507
315
|
}
|
|
508
316
|
/** Responde con texto. / Replies with text. */
|
|
509
|
-
async text(caption, extra = {}) {
|
|
510
|
-
return Message.text(this._wa, this._raw.cid, caption, { ...extra, mid: this._raw.id });
|
|
511
|
-
}
|
|
317
|
+
async text(caption, extra = {}) { return send(this._init, this._raw.cid, { text: caption }, undefined, { ...extra, mid: this._raw.id }); }
|
|
512
318
|
/** Responde con imagen. / Replies with an image. */
|
|
513
|
-
async image(buf, extra = {}) {
|
|
514
|
-
return Message.image(this._wa, this._raw.cid, buf, { ...extra, mid: this._raw.id });
|
|
515
|
-
}
|
|
319
|
+
async image(buf, extra = {}) { return send(this._init, this._raw.cid, { image: buf, caption: extra.caption }, buf, { ...extra, mid: this._raw.id }); }
|
|
516
320
|
/** Responde con video. / Replies with a video. */
|
|
517
|
-
async video(buf, extra = {}) {
|
|
518
|
-
return Message.video(this._wa, this._raw.cid, buf, { ...extra, mid: this._raw.id });
|
|
519
|
-
}
|
|
321
|
+
async video(buf, extra = {}) { return send(this._init, this._raw.cid, { video: buf, caption: extra.caption }, buf, { ...extra, mid: this._raw.id }); }
|
|
520
322
|
/** Responde con audio. / Replies with audio. */
|
|
521
|
-
async audio(buf, extra = {}) {
|
|
522
|
-
return Message.audio(this._wa, this._raw.cid, buf, { ...extra, mid: this._raw.id });
|
|
523
|
-
}
|
|
323
|
+
async audio(buf, extra = {}) { return send(this._init, this._raw.cid, { audio: buf, ptt: extra.ptt ?? true }, buf, { ...extra, mid: this._raw.id }); }
|
|
524
324
|
/** Responde con ubicación. / Replies with a location. */
|
|
525
|
-
async location(loc, extra = {}) {
|
|
526
|
-
return Message.location(this._wa, this._raw.cid, loc, { ...extra, mid: this._raw.id });
|
|
527
|
-
}
|
|
325
|
+
async location(loc, extra = {}) { return send(this._init, this._raw.cid, { location: { degreesLatitude: loc.lat, degreesLongitude: loc.lng } }, undefined, { ...extra, mid: this._raw.id }); }
|
|
528
326
|
/** Responde con encuesta. / Replies with a poll. */
|
|
529
327
|
async poll(input, extra = {}) {
|
|
530
|
-
return
|
|
328
|
+
return send(this._init, this._raw.cid, poll_of(input, extra.multiple ?? false), undefined, { ...extra, mid: this._raw.id }, { multiple: extra.multiple ?? false });
|
|
531
329
|
}
|
|
532
330
|
/** Responde con documento. / Replies with a document. */
|
|
533
331
|
async document(buf, extra) {
|
|
534
|
-
return
|
|
332
|
+
return send(this._init, this._raw.cid, { document: buf, fileName: extra.file_name, mimetype: extra.mimetype ?? 'application/octet-stream', caption: extra.caption }, buf, { ...extra, mid: this._raw.id });
|
|
535
333
|
}
|
|
536
334
|
/** Responde con tarjeta(s) de contacto. / Replies with contact card(s). */
|
|
537
335
|
async vcard(contacts, extra = {}) {
|
|
538
|
-
|
|
336
|
+
const cards = vcards_of(contacts);
|
|
337
|
+
return send(this._init, this._raw.cid, cards.content, cards.binary, { ...extra, mid: this._raw.id });
|
|
539
338
|
}
|
|
540
339
|
/** Responde con evento. / Replies with an event. */
|
|
541
340
|
async event(data, extra = {}) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* Obtiene un mensaje por chat y id.
|
|
546
|
-
* Retrieves a message by chat and id.
|
|
547
|
-
*
|
|
548
|
-
* @param wa - Cliente dueño / Owner client
|
|
549
|
-
* @param cid - Identificador del chat / Chat identifier
|
|
550
|
-
* @param mid - Identificador del mensaje / Message identifier
|
|
551
|
-
* @returns Mensaje o null / Message or null
|
|
552
|
-
*/
|
|
553
|
-
static async get(wa, cid, mid) {
|
|
554
|
-
const jid = await (0, internal_1.internals)(wa).resolve_jid(cid);
|
|
555
|
-
if (jid) {
|
|
556
|
-
const doc = (0, store_1.deserialize)(await wa.engine.get(`/chat/${jid}/message/${mid}`));
|
|
557
|
-
if (doc)
|
|
558
|
-
return message(wa, doc);
|
|
559
|
-
}
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Pagina los mensajes de un chat desde el más reciente.
|
|
564
|
-
* Paginates chat messages from the most recent one.
|
|
565
|
-
*
|
|
566
|
-
* @param wa - Cliente dueño / Owner client
|
|
567
|
-
* @param cid - Identificador del chat / Chat identifier
|
|
568
|
-
* @param offset - Desplazamiento / Offset
|
|
569
|
-
* @param limit - Tamaño de página / Page size
|
|
570
|
-
* @returns Página de mensajes / Message page
|
|
571
|
-
*/
|
|
572
|
-
static async list(wa, cid, offset = 0, limit = 50) {
|
|
573
|
-
const jid = await (0, internal_1.internals)(wa).resolve_jid(cid);
|
|
574
|
-
if (jid) {
|
|
575
|
-
return (await wa.engine.list(`/chat/${jid}/message`, offset, limit))
|
|
576
|
-
.map((raw) => (0, store_1.deserialize)(raw))
|
|
577
|
-
.filter((doc) => doc !== null)
|
|
578
|
-
.map((doc) => message(wa, doc));
|
|
579
|
-
}
|
|
580
|
-
return [];
|
|
581
|
-
}
|
|
582
|
-
/** Envía texto. / Sends text. */
|
|
583
|
-
static async text(wa, cid, caption, extra = {}) {
|
|
584
|
-
return send(wa, cid, { text: caption }, undefined, extra);
|
|
585
|
-
}
|
|
586
|
-
/** Envía imagen. / Sends an image. */
|
|
587
|
-
static async image(wa, cid, buf, extra = {}) {
|
|
588
|
-
return send(wa, cid, { image: buf, caption: extra.caption }, buf, extra);
|
|
589
|
-
}
|
|
590
|
-
/** Envía video. / Sends a video. */
|
|
591
|
-
static async video(wa, cid, buf, extra = {}) {
|
|
592
|
-
return send(wa, cid, { video: buf, caption: extra.caption }, buf, extra);
|
|
593
|
-
}
|
|
594
|
-
/** Envía audio. / Sends audio. */
|
|
595
|
-
static async audio(wa, cid, buf, extra = {}) {
|
|
596
|
-
return send(wa, cid, { audio: buf, ptt: extra.ptt ?? true }, buf, extra);
|
|
597
|
-
}
|
|
598
|
-
/** Envía ubicación. / Sends a location. */
|
|
599
|
-
static async location(wa, cid, loc, extra = {}) {
|
|
600
|
-
return send(wa, cid, { location: { degreesLatitude: loc.lat, degreesLongitude: loc.lng } }, undefined, extra);
|
|
601
|
-
}
|
|
602
|
-
/** Envía encuesta. / Sends a poll. */
|
|
603
|
-
static async poll(wa, cid, input, extra = {}) {
|
|
604
|
-
const multiple = extra.multiple ?? false;
|
|
605
|
-
return send(wa, cid, {
|
|
606
|
-
poll: {
|
|
607
|
-
name: input.content,
|
|
608
|
-
values: input.options.map((option) => option.content),
|
|
609
|
-
selectableCount: multiple ? 0 : 1,
|
|
610
|
-
},
|
|
611
|
-
}, undefined, extra, { multiple });
|
|
612
|
-
}
|
|
613
|
-
/** Envía documento. / Sends a document. */
|
|
614
|
-
static async document(wa, cid, buf, extra) {
|
|
615
|
-
return send(wa, cid, { document: buf, fileName: extra.file_name, mimetype: extra.mimetype ?? 'application/octet-stream', caption: extra.caption }, buf, extra);
|
|
616
|
-
}
|
|
617
|
-
/** Envía tarjeta(s) de contacto. / Sends contact card(s). */
|
|
618
|
-
static async vcard(wa, cid, contacts, extra = {}) {
|
|
619
|
-
const built = contacts.map((entry) => ({
|
|
620
|
-
displayName: entry.name,
|
|
621
|
-
vcard: [
|
|
622
|
-
'BEGIN:VCARD',
|
|
623
|
-
'VERSION:3.0',
|
|
624
|
-
`FN:${entry.name}`,
|
|
625
|
-
`TEL;type=CELL;waid=${entry.phone.replace(/\D+/g, '')}:${entry.phone}`,
|
|
626
|
-
'END:VCARD',
|
|
627
|
-
].join('\n'),
|
|
628
|
-
}));
|
|
629
|
-
return send(wa, cid, { contacts: { contacts: built } }, Buffer.from(built.map((entry) => entry.vcard).join('\n'), 'utf-8'), extra);
|
|
630
|
-
}
|
|
631
|
-
/** Envía evento. / Sends an event. */
|
|
632
|
-
static async event(wa, cid, data, extra = {}) {
|
|
633
|
-
const binary = Buffer.from(JSON.stringify({ name: data.name, caption: data.caption, start: data.start.getTime(), end: data.end?.getTime() ?? null }), 'utf-8');
|
|
634
|
-
return send(wa, cid, {
|
|
635
|
-
event: {
|
|
636
|
-
name: data.name,
|
|
637
|
-
description: data.caption,
|
|
638
|
-
startDate: data.start,
|
|
639
|
-
endDate: data.end,
|
|
640
|
-
location: data.place ? { degreesLatitude: data.place.lat, degreesLongitude: data.place.lng } : undefined,
|
|
641
|
-
},
|
|
642
|
-
}, binary, extra);
|
|
643
|
-
}
|
|
644
|
-
/** Reacciona a un mensaje por id. / Reacts to a message by id. */
|
|
645
|
-
static async react(wa, cid, mid, emoji) {
|
|
646
|
-
const msg = await Message.get(wa, cid, mid);
|
|
647
|
-
return msg ? msg.react(emoji) : false;
|
|
648
|
-
}
|
|
649
|
-
/** Destaca un mensaje por id. / Stars a message by id. */
|
|
650
|
-
static async star(wa, cid, mid, value) {
|
|
651
|
-
const msg = await Message.get(wa, cid, mid);
|
|
652
|
-
return msg ? msg.star(value) : false;
|
|
653
|
-
}
|
|
654
|
-
/** Marca un mensaje como leído por id. / Marks a message as read by id. */
|
|
655
|
-
static async seen(wa, cid, mid) {
|
|
656
|
-
const msg = await Message.get(wa, cid, mid);
|
|
657
|
-
return msg ? msg.seen() : false;
|
|
658
|
-
}
|
|
659
|
-
/** Edita un mensaje por id. / Edits a message by id. */
|
|
660
|
-
static async edit(wa, cid, mid, caption) {
|
|
661
|
-
const msg = await Message.get(wa, cid, mid);
|
|
662
|
-
return msg ? msg.edit(caption) : false;
|
|
663
|
-
}
|
|
664
|
-
/** Reenvía un mensaje por id. / Forwards a message by id. */
|
|
665
|
-
static async forward(wa, cid, mid, target) {
|
|
666
|
-
const msg = await Message.get(wa, cid, mid);
|
|
667
|
-
return msg ? msg.forward(target) : false;
|
|
668
|
-
}
|
|
669
|
-
/** Elimina un mensaje por id. / Deletes a message by id. */
|
|
670
|
-
static async delete(wa, cid, mid, all = false) {
|
|
671
|
-
const msg = await Message.get(wa, cid, mid);
|
|
672
|
-
return msg ? msg.delete(all) : false;
|
|
673
|
-
}
|
|
674
|
-
/** Reacciones de un mensaje por id. / Reactions of a message by id. */
|
|
675
|
-
static async reactions(wa, cid, mid) {
|
|
676
|
-
const msg = await Message.get(wa, cid, mid);
|
|
677
|
-
return msg ? msg.reactions() : [];
|
|
341
|
+
const built = event_of(data);
|
|
342
|
+
return send(this._init, this._raw.cid, built.content, built.binary, { ...extra, mid: this._raw.id });
|
|
678
343
|
}
|
|
679
344
|
}
|
|
680
|
-
exports.
|
|
345
|
+
exports.default = Message;
|
|
681
346
|
/**
|
|
682
347
|
* Mensaje de texto; `preview()` expone la tarjeta del enlace embebido.
|
|
683
348
|
* Text message; `preview()` exposes the embedded link card.
|
|
684
349
|
*/
|
|
685
350
|
class Text extends Message {
|
|
686
|
-
/**
|
|
687
|
-
* Preview del enlace del texto, o null cuando no trae metadata.
|
|
688
|
-
* Text link preview, or null when it carries no metadata.
|
|
689
|
-
*
|
|
690
|
-
* @returns { link, name, content, thumb } o null / { link, name, content, thumb } or null
|
|
691
|
-
*/
|
|
351
|
+
/** Preview del enlace, o null cuando el texto no trae metadata. / Link preview, or null when the text carries no metadata. */
|
|
692
352
|
async preview() {
|
|
693
353
|
const ext = this._raw.raw.message?.extendedTextMessage;
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
name: ext.title ?? null,
|
|
698
|
-
content: ext.description ?? null,
|
|
699
|
-
thumb: to_buffer(ext.jpegThumbnail),
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
return null;
|
|
354
|
+
return ext?.matchedText && (ext.title || ext.description)
|
|
355
|
+
? { link: ext.matchedText, name: ext.title ?? null, content: ext.description ?? null, thumb: to_buffer(ext.jpegThumbnail) }
|
|
356
|
+
: null;
|
|
703
357
|
}
|
|
704
358
|
}
|
|
705
359
|
exports.Text = Text;
|
|
706
360
|
/**
|
|
707
|
-
*
|
|
708
|
-
*
|
|
361
|
+
* Base de los mensajes con binario: dimensiones, peso, miniatura y descarga.
|
|
362
|
+
* Base for binary messages: dimensions, size, thumbnail and download.
|
|
709
363
|
*/
|
|
710
|
-
class
|
|
711
|
-
/** @internal */
|
|
364
|
+
class Media extends Message {
|
|
365
|
+
/** @internal Bloque de media del raw, común a los cinco tipos. / Raw media block, shared by the five types. */
|
|
712
366
|
get _media() {
|
|
713
|
-
|
|
367
|
+
const msg = unwrap(this._raw.raw.message ?? {});
|
|
368
|
+
return (msg.imageMessage ?? msg.videoMessage ?? msg.audioMessage ?? msg.stickerMessage ?? msg.documentMessage ?? null);
|
|
714
369
|
}
|
|
715
370
|
/** Ancho en píxeles. / Width in pixels. */
|
|
716
|
-
get width() {
|
|
717
|
-
return this._media?.width ?? 0;
|
|
718
|
-
}
|
|
371
|
+
get width() { return this._media?.width ?? 0; }
|
|
719
372
|
/** Alto en píxeles. / Height in pixels. */
|
|
720
|
-
get height() {
|
|
721
|
-
return this._media?.height ?? 0;
|
|
722
|
-
}
|
|
373
|
+
get height() { return this._media?.height ?? 0; }
|
|
723
374
|
/** Peso en bytes. / Size in bytes. */
|
|
724
|
-
get size() {
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Miniatura JPEG embebida, o null.
|
|
729
|
-
* Embedded JPEG thumbnail, or null.
|
|
730
|
-
*
|
|
731
|
-
* @returns Buffer de la miniatura o null / Thumbnail buffer or null
|
|
732
|
-
*/
|
|
733
|
-
async thumb() {
|
|
734
|
-
return to_buffer(this._media?.jpegThumbnail);
|
|
735
|
-
}
|
|
375
|
+
get size() { return Number(this._media?.fileLength?.toString() ?? 0); }
|
|
376
|
+
/** Miniatura JPEG embebida, o null. / Embedded JPEG thumbnail, or null. */
|
|
377
|
+
async thumb() { return to_buffer(this._media?.jpegThumbnail); }
|
|
378
|
+
/** Binario del media: el persistido, o la descarga de baileys. / Media binary: the persisted one, or the baileys download. */
|
|
736
379
|
async content() {
|
|
737
|
-
|
|
380
|
+
const cached = await super.content();
|
|
381
|
+
if (cached.length)
|
|
382
|
+
return cached;
|
|
383
|
+
const raw = await (0, baileys_1.downloadMediaMessage)(this._raw.raw, 'buffer', {}).catch(() => Buffer.alloc(0));
|
|
384
|
+
return Buffer.isBuffer(raw) ? raw : Buffer.alloc(0);
|
|
385
|
+
}
|
|
386
|
+
/** Stream del media sin acumularlo cuando hay que descargar. / Media stream without buffering when a download is needed. */
|
|
387
|
+
async stream() {
|
|
388
|
+
const cached = await super.content();
|
|
389
|
+
return cached.length
|
|
390
|
+
? node_stream_1.Readable.from(cached)
|
|
391
|
+
: (await (0, baileys_1.downloadMediaMessage)(this._raw.raw, 'stream', {}).catch(() => node_stream_1.Readable.from(Buffer.alloc(0))));
|
|
738
392
|
}
|
|
739
393
|
}
|
|
394
|
+
/** Mensaje de imagen. / Image message. */
|
|
395
|
+
class Image extends Media {
|
|
396
|
+
}
|
|
740
397
|
exports.Image = Image;
|
|
741
|
-
/**
|
|
742
|
-
|
|
743
|
-
* Video message: dimensions, duration, size and thumbnail.
|
|
744
|
-
*/
|
|
745
|
-
class Video extends Message {
|
|
746
|
-
/** @internal */
|
|
747
|
-
get _media() {
|
|
748
|
-
return unwrap(this._raw.raw.message ?? {}).videoMessage;
|
|
749
|
-
}
|
|
750
|
-
/** Ancho en píxeles. / Width in pixels. */
|
|
751
|
-
get width() {
|
|
752
|
-
return this._media?.width ?? 0;
|
|
753
|
-
}
|
|
754
|
-
/** Alto en píxeles. / Height in pixels. */
|
|
755
|
-
get height() {
|
|
756
|
-
return this._media?.height ?? 0;
|
|
757
|
-
}
|
|
398
|
+
/** Mensaje de video. / Video message. */
|
|
399
|
+
class Video extends Media {
|
|
758
400
|
/** Duración en segundos. / Duration in seconds. */
|
|
759
|
-
get duration() {
|
|
760
|
-
return this._media?.seconds ?? 0;
|
|
761
|
-
}
|
|
762
|
-
/** Peso en bytes. / Size in bytes. */
|
|
763
|
-
get size() {
|
|
764
|
-
return to_number(this._media?.fileLength);
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Miniatura JPEG embebida, o null.
|
|
768
|
-
* Embedded JPEG thumbnail, or null.
|
|
769
|
-
*
|
|
770
|
-
* @returns Buffer de la miniatura o null / Thumbnail buffer or null
|
|
771
|
-
*/
|
|
772
|
-
async thumb() {
|
|
773
|
-
return to_buffer(this._media?.jpegThumbnail);
|
|
774
|
-
}
|
|
775
|
-
async content() {
|
|
776
|
-
return drain(await this.stream());
|
|
777
|
-
}
|
|
401
|
+
get duration() { return this._media?.seconds ?? 0; }
|
|
778
402
|
}
|
|
779
403
|
exports.Video = Video;
|
|
780
|
-
/**
|
|
781
|
-
|
|
782
|
-
* Audio message: voice note or file, with the protocol waveform.
|
|
783
|
-
*/
|
|
784
|
-
class Audio extends Message {
|
|
785
|
-
/** @internal */
|
|
786
|
-
get _media() {
|
|
787
|
-
return unwrap(this._raw.raw.message ?? {}).audioMessage;
|
|
788
|
-
}
|
|
404
|
+
/** Mensaje de audio: nota de voz o archivo. / Audio message: voice note or file. */
|
|
405
|
+
class Audio extends Media {
|
|
789
406
|
/** true si es nota de voz. / true when push-to-talk. */
|
|
790
|
-
get ptt() {
|
|
791
|
-
return this._media?.ptt === true;
|
|
792
|
-
}
|
|
407
|
+
get ptt() { return this._media?.ptt === true; }
|
|
793
408
|
/** Duración en segundos. / Duration in seconds. */
|
|
794
|
-
get duration() {
|
|
795
|
-
return this._media?.seconds ?? 0;
|
|
796
|
-
}
|
|
797
|
-
/** Peso en bytes. / Size in bytes. */
|
|
798
|
-
get size() {
|
|
799
|
-
return to_number(this._media?.fileLength);
|
|
800
|
-
}
|
|
409
|
+
get duration() { return this._media?.seconds ?? 0; }
|
|
801
410
|
/** Forma de onda 0-100 lista para pintar. / Paint-ready 0-100 waveform. */
|
|
802
|
-
get waveform() {
|
|
803
|
-
const wave = this._media?.waveform;
|
|
804
|
-
const bytes = wave instanceof Uint8Array ? wave : typeof wave === 'string' ? Buffer.from(wave, 'base64') : Buffer.alloc(0);
|
|
805
|
-
return Array.from(bytes);
|
|
806
|
-
}
|
|
807
|
-
async content() {
|
|
808
|
-
return drain(await this.stream());
|
|
809
|
-
}
|
|
411
|
+
get waveform() { return Array.from(to_buffer(this._media?.waveform) ?? []); }
|
|
810
412
|
}
|
|
811
413
|
exports.Audio = Audio;
|
|
812
|
-
/**
|
|
813
|
-
|
|
814
|
-
* Sticker message: dimensions, size and animation.
|
|
815
|
-
*/
|
|
816
|
-
class Sticker extends Message {
|
|
817
|
-
/** @internal */
|
|
818
|
-
get _media() {
|
|
819
|
-
return unwrap(this._raw.raw.message ?? {}).stickerMessage;
|
|
820
|
-
}
|
|
821
|
-
/** Ancho en píxeles. / Width in pixels. */
|
|
822
|
-
get width() {
|
|
823
|
-
return this._media?.width ?? 0;
|
|
824
|
-
}
|
|
825
|
-
/** Alto en píxeles. / Height in pixels. */
|
|
826
|
-
get height() {
|
|
827
|
-
return this._media?.height ?? 0;
|
|
828
|
-
}
|
|
414
|
+
/** Mensaje de sticker. / Sticker message. */
|
|
415
|
+
class Sticker extends Media {
|
|
829
416
|
/** true si el sticker es animado. / true when animated. */
|
|
830
|
-
get animated() {
|
|
831
|
-
return this._media?.isAnimated === true;
|
|
832
|
-
}
|
|
833
|
-
/** Peso en bytes. / Size in bytes. */
|
|
834
|
-
get size() {
|
|
835
|
-
return to_number(this._media?.fileLength);
|
|
836
|
-
}
|
|
837
|
-
async content() {
|
|
838
|
-
return drain(await this.stream());
|
|
839
|
-
}
|
|
417
|
+
get animated() { return this._media?.isAnimated === true; }
|
|
840
418
|
}
|
|
841
419
|
exports.Sticker = Sticker;
|
|
842
|
-
/**
|
|
843
|
-
|
|
844
|
-
* Document message; the actual MIME lives in the base `mime`.
|
|
845
|
-
*/
|
|
846
|
-
class Document extends Message {
|
|
847
|
-
/** @internal */
|
|
848
|
-
get _media() {
|
|
849
|
-
return unwrap(this._raw.raw.message ?? {}).documentMessage;
|
|
850
|
-
}
|
|
420
|
+
/** Mensaje de documento; el MIME real vive en `mime`. / Document message; the actual MIME lives in `mime`. */
|
|
421
|
+
class Document extends Media {
|
|
851
422
|
/** Nombre del archivo. / File name. */
|
|
852
|
-
get name() {
|
|
853
|
-
return this._media?.fileName ?? '';
|
|
854
|
-
}
|
|
423
|
+
get name() { return this._media?.fileName ?? ''; }
|
|
855
424
|
/** Número de páginas (PDF); 0 cuando no aplica. / Page count (PDF); 0 when not applicable. */
|
|
856
|
-
get pages() {
|
|
857
|
-
return this._media?.pageCount ?? 0;
|
|
858
|
-
}
|
|
859
|
-
/** Peso en bytes. / Size in bytes. */
|
|
860
|
-
get size() {
|
|
861
|
-
return to_number(this._media?.fileLength);
|
|
862
|
-
}
|
|
863
|
-
async content() {
|
|
864
|
-
return drain(await this.stream());
|
|
865
|
-
}
|
|
425
|
+
get pages() { return this._media?.pageCount ?? 0; }
|
|
866
426
|
}
|
|
867
427
|
exports.Document = Document;
|
|
868
|
-
/**
|
|
869
|
-
* Mensaje de ubicación, fija o en vivo.
|
|
870
|
-
* Location message, static or live.
|
|
871
|
-
*/
|
|
428
|
+
/** Mensaje de ubicación, fija o en vivo. / Location message, static or live. */
|
|
872
429
|
class Location extends Message {
|
|
873
|
-
/** @internal */
|
|
874
|
-
get _loc() {
|
|
875
|
-
return this._raw.raw.message?.locationMessage ?? this._raw.raw.message?.liveLocationMessage;
|
|
876
|
-
}
|
|
877
430
|
/** Latitud en grados. / Latitude in degrees. */
|
|
878
|
-
get lat() {
|
|
879
|
-
return this._loc?.degreesLatitude ?? 0;
|
|
880
|
-
}
|
|
431
|
+
get lat() { return (this._raw.raw.message?.locationMessage ?? this._raw.raw.message?.liveLocationMessage)?.degreesLatitude ?? 0; }
|
|
881
432
|
/** Longitud en grados. / Longitude in degrees. */
|
|
882
|
-
get lng() {
|
|
883
|
-
return this._loc?.degreesLongitude ?? 0;
|
|
884
|
-
}
|
|
433
|
+
get lng() { return (this._raw.raw.message?.locationMessage ?? this._raw.raw.message?.liveLocationMessage)?.degreesLongitude ?? 0; }
|
|
885
434
|
/** true si es ubicación en tiempo real. / true when live location. */
|
|
886
|
-
get live() {
|
|
887
|
-
return Boolean(this._raw.raw.message?.liveLocationMessage);
|
|
888
|
-
}
|
|
435
|
+
get live() { return Boolean(this._raw.raw.message?.liveLocationMessage); }
|
|
889
436
|
/** URL de Google Maps de la coordenada. / Google Maps URL for the coordinate. */
|
|
890
|
-
get link() {
|
|
891
|
-
return `https://www.google.com/maps/@${this.lat},${this.lng},15z`;
|
|
892
|
-
}
|
|
437
|
+
get link() { return `https://www.google.com/maps/@${this.lat},${this.lng},15z`; }
|
|
893
438
|
}
|
|
894
439
|
exports.Location = Location;
|
|
895
440
|
/**
|
|
@@ -897,7 +442,7 @@ exports.Location = Location;
|
|
|
897
442
|
* Poll message: options with counts, per-contact votes and self-voting.
|
|
898
443
|
*/
|
|
899
444
|
class Poll extends Message {
|
|
900
|
-
/** @internal */
|
|
445
|
+
/** @internal Bloque de la encuesta en el raw. / Raw poll block. */
|
|
901
446
|
get _poll() {
|
|
902
447
|
const msg = this._raw.raw.message;
|
|
903
448
|
return msg?.pollCreationMessage ?? msg?.pollCreationMessageV2 ?? msg?.pollCreationMessageV3;
|
|
@@ -906,166 +451,111 @@ class Poll extends Message {
|
|
|
906
451
|
get _updates() {
|
|
907
452
|
return (this._raw.raw.pollUpdates ?? []).map((update) => ({
|
|
908
453
|
...update,
|
|
909
|
-
vote: update.vote
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
: update.vote,
|
|
454
|
+
vote: update.vote && {
|
|
455
|
+
...update.vote,
|
|
456
|
+
selectedOptions: (update.vote.selectedOptions ?? []).map((option) => (typeof option === 'string' ? Buffer.from(option, 'base64') : option)),
|
|
457
|
+
},
|
|
915
458
|
}));
|
|
916
459
|
}
|
|
917
460
|
/** true si admite varias respuestas. / true when multi-select. */
|
|
918
461
|
get multiple() {
|
|
919
|
-
|
|
920
|
-
return this._raw.multiple;
|
|
921
|
-
}
|
|
922
|
-
return (this._poll?.selectableOptionsCount ?? 1) !== 1;
|
|
462
|
+
return typeof this._raw.multiple === 'boolean' ? this._raw.multiple : (this._poll?.selectableOptionsCount ?? 1) !== 1;
|
|
923
463
|
}
|
|
924
464
|
/** Opciones con su conteo de votos. / Options with their vote counts. */
|
|
925
465
|
get options() {
|
|
926
|
-
const aggregated = (0, baileys_1.getAggregateVotesInPollMessage)({ message: this._raw.raw.message ?? undefined, pollUpdates: this._updates },
|
|
466
|
+
const aggregated = (0, baileys_1.getAggregateVotesInPollMessage)({ message: this._raw.raw.message ?? undefined, pollUpdates: this._updates }, this._init.socket.user?.id);
|
|
927
467
|
const counts = new Map(aggregated.map((entry) => [entry.name, entry.voters.length]));
|
|
928
|
-
return (this._poll?.options ?? []).map((option) => ({
|
|
929
|
-
name: option.optionName ?? '',
|
|
930
|
-
count: counts.get(option.optionName ?? '') ?? 0,
|
|
931
|
-
}));
|
|
468
|
+
return (this._poll?.options ?? []).map((option) => ({ name: option.optionName ?? '', count: counts.get(option.optionName ?? '') ?? 0 }));
|
|
932
469
|
}
|
|
933
|
-
/**
|
|
934
|
-
* Votos individuales: opción elegida y teléfono del votante.
|
|
935
|
-
* Individual votes: chosen option and voter phone.
|
|
936
|
-
*
|
|
937
|
-
* @returns Lista de votos / Vote list
|
|
938
|
-
*/
|
|
470
|
+
/** Votos individuales: opción elegida y teléfono del votante. / Individual votes: chosen option and voter phone. */
|
|
939
471
|
async votes() {
|
|
940
|
-
const aggregated = (0, baileys_1.getAggregateVotesInPollMessage)({ message: this._raw.raw.message ?? undefined, pollUpdates: this._updates },
|
|
472
|
+
const aggregated = (0, baileys_1.getAggregateVotesInPollMessage)({ message: this._raw.raw.message ?? undefined, pollUpdates: this._updates }, this._init.socket.user?.id);
|
|
941
473
|
const result = [];
|
|
942
474
|
for (const entry of aggregated) {
|
|
943
475
|
for (const voter of entry.voters) {
|
|
944
|
-
const jid = await (0,
|
|
476
|
+
const jid = await (0, store_1.jid_of)(this._init.engine, voter, this._init.socket);
|
|
945
477
|
result.push({ name: entry.name, contact: (jid ?? voter).split('@')[0].split(':')[0] });
|
|
946
478
|
}
|
|
947
479
|
}
|
|
948
480
|
return result;
|
|
949
481
|
}
|
|
950
482
|
/**
|
|
951
|
-
* Vota
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
957
|
-
* decrypt fine, but WhatsApp does not propagate votes emitted from a linked
|
|
958
|
-
* (companion) device.
|
|
483
|
+
* Vota con uno o varios índices: cifra el voto (HMAC+AES-GCM) y lo enruta al chat @lid
|
|
484
|
+
* con la identidad LID propia. Best-effort: WhatsApp no propaga el voto emitido desde un
|
|
485
|
+
* dispositivo vinculado.
|
|
486
|
+
* Votes with one or more indexes: encrypts the vote (HMAC+AES-GCM) and routes it to the
|
|
487
|
+
* @lid chat with the own LID identity. Best-effort: WhatsApp does not propagate votes
|
|
488
|
+
* emitted from a linked device.
|
|
959
489
|
*
|
|
960
490
|
* @param index - Índice o índices de la opción / Option index or indexes
|
|
961
491
|
* @returns true si el voto se emitió / true when the vote was relayed
|
|
962
492
|
*/
|
|
963
493
|
async select(index) {
|
|
494
|
+
const { socket, engine } = this._init;
|
|
964
495
|
const doc = this._raw;
|
|
965
|
-
const
|
|
966
|
-
const
|
|
967
|
-
.filter((i) => i >= 0 && i < opts.length)
|
|
968
|
-
.map((i) => (0, baileys_1.sha256)(Buffer.from(opts[i].optionName ?? '')));
|
|
496
|
+
const options = this._poll?.options ?? [];
|
|
497
|
+
const selected = (Array.isArray(index) ? index : [index]).filter((i) => i >= 0 && i < options.length).map((i) => (0, baileys_1.sha256)(Buffer.from(options[i].optionName ?? '')));
|
|
969
498
|
const secret_raw = doc.raw.message?.messageContextInfo?.messageSecret;
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
if (!poll_enc_key || !socket || selected_options.length === 0) {
|
|
499
|
+
const secret = typeof secret_raw === 'string' ? Buffer.from(secret_raw, 'base64') : secret_raw;
|
|
500
|
+
if (!secret || selected.length === 0)
|
|
973
501
|
return false;
|
|
974
|
-
}
|
|
975
|
-
const
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
const
|
|
988
|
-
const
|
|
989
|
-
const poll_creator_jid = (0, baileys_1.jidNormalizedUser)(poll_key.fromMe
|
|
990
|
-
? self_for_send
|
|
991
|
-
: poll_key.remoteJid?.endsWith('@lid')
|
|
992
|
-
? poll_key.remoteJid
|
|
993
|
-
: (0, baileys_1.getKeyAuthor)(poll_key, self_id));
|
|
994
|
-
const sign = Buffer.concat([
|
|
995
|
-
Buffer.from(doc.id),
|
|
996
|
-
Buffer.from(poll_creator_jid),
|
|
997
|
-
Buffer.from(voter_jid),
|
|
998
|
-
Buffer.from('Poll Vote'),
|
|
999
|
-
new Uint8Array([1]),
|
|
1000
|
-
]);
|
|
1001
|
-
const enc_key = (0, baileys_1.hmacSign)(sign, (0, baileys_1.hmacSign)(poll_enc_key, new Uint8Array(32), 'sha256'), 'sha256');
|
|
1002
|
-
const enc_iv = (0, node_crypto_1.randomBytes)(12);
|
|
1003
|
-
const enc_payload = (0, baileys_1.aesEncryptGCM)(baileys_1.proto.Message.PollVoteMessage.encode({ selectedOptions: selected_options }).finish(), enc_key, enc_iv, Buffer.from(`${doc.id}\x00${voter_jid}`));
|
|
1004
|
-
const msg_id = (0, baileys_1.generateMessageID)();
|
|
502
|
+
const key = doc.raw.key ?? {};
|
|
503
|
+
const self = socket.user?.id ?? '';
|
|
504
|
+
const dest = key.remoteJid?.endsWith('@lid') ? key.remoteJid
|
|
505
|
+
: doc.cid.endsWith('@lid') ? doc.cid
|
|
506
|
+
: (0, store_1.deserialize)(await engine.get(`/contact/${doc.cid}`))?.lid
|
|
507
|
+
?? await socket.signalRepository?.lidMapping?.getLIDForPN(doc.cid).catch(() => null)
|
|
508
|
+
?? doc.cid;
|
|
509
|
+
const mine = dest.endsWith('@lid') && socket.user?.lid ? socket.user.lid : self;
|
|
510
|
+
const voter = (0, baileys_1.jidNormalizedUser)(mine);
|
|
511
|
+
const creator = (0, baileys_1.jidNormalizedUser)(key.fromMe ? mine : key.remoteJid?.endsWith('@lid') ? key.remoteJid : (0, baileys_1.getKeyAuthor)(key, self));
|
|
512
|
+
const sign = Buffer.concat([Buffer.from(doc.id), Buffer.from(creator), Buffer.from(voter), Buffer.from('Poll Vote'), new Uint8Array([1])]);
|
|
513
|
+
const enc_key = (0, baileys_1.hmacSign)(sign, (0, baileys_1.hmacSign)(secret, new Uint8Array(32), 'sha256'), 'sha256');
|
|
514
|
+
const iv = (0, node_crypto_1.randomBytes)(12);
|
|
515
|
+
const payload = (0, baileys_1.aesEncryptGCM)(baileys_1.proto.Message.PollVoteMessage.encode({ selectedOptions: selected }).finish(), enc_key, iv, Buffer.from(`${doc.id}\x00${voter}`));
|
|
516
|
+
const mid = (0, baileys_1.generateMessageID)();
|
|
1005
517
|
await socket.relayMessage(dest, {
|
|
1006
518
|
pollUpdateMessage: {
|
|
1007
519
|
pollCreationMessageKey: dest === doc.cid ? doc.raw.key : { ...doc.raw.key, remoteJid: dest },
|
|
1008
|
-
vote: { encPayload:
|
|
520
|
+
vote: { encPayload: payload, encIv: iv },
|
|
1009
521
|
senderTimestampMs: Date.now(),
|
|
1010
522
|
},
|
|
1011
|
-
}, { messageId:
|
|
523
|
+
}, { messageId: mid });
|
|
1012
524
|
(0, baileys_1.updateMessageWithPollUpdate)(doc.raw, {
|
|
1013
|
-
pollUpdateMessageKey: { remoteJid: doc.raw.key?.remoteJid ?? doc.cid, fromMe: true, id:
|
|
1014
|
-
vote: { selectedOptions:
|
|
525
|
+
pollUpdateMessageKey: { remoteJid: doc.raw.key?.remoteJid ?? doc.cid, fromMe: true, id: mid },
|
|
526
|
+
vote: { selectedOptions: selected },
|
|
1015
527
|
senderTimestampMs: Date.now(),
|
|
1016
528
|
});
|
|
1017
|
-
await
|
|
1018
|
-
this.
|
|
529
|
+
await engine.set(`/chat/${doc.cid}/message/${doc.id}`, (0, store_1.serialize)(doc), doc.created_at);
|
|
530
|
+
this._init.wa.emit('message:updated', this, await this.chat(), this._init.wa);
|
|
1019
531
|
return true;
|
|
1020
532
|
}
|
|
1021
533
|
}
|
|
1022
534
|
exports.Poll = Poll;
|
|
1023
|
-
/**
|
|
1024
|
-
* Mensaje de tarjeta(s) de contacto.
|
|
1025
|
-
* Contact card(s) message.
|
|
1026
|
-
*/
|
|
535
|
+
/** Mensaje de tarjeta(s) de contacto. / Contact card(s) message. */
|
|
1027
536
|
class VCard extends Message {
|
|
1028
537
|
/** Contactos de la tarjeta. / Card contacts. */
|
|
1029
538
|
get contacts() {
|
|
1030
539
|
const msg = this._raw.raw.message;
|
|
1031
540
|
const raw = msg?.contactsArrayMessage?.contacts ?? (msg?.contactMessage ? [msg.contactMessage] : []);
|
|
1032
|
-
return raw.map((card) => {
|
|
1033
|
-
const tel = (card.vcard ?? '').match(/TEL[^:]*:(.+)/);
|
|
1034
|
-
return { name: card.displayName ?? '', phone: tel ? tel[1].trim() : '' };
|
|
1035
|
-
});
|
|
541
|
+
return raw.map((card) => ({ name: card.displayName ?? '', phone: (card.vcard ?? '').match(/TEL[^:]*:(.+)/)?.[1].trim() ?? '' }));
|
|
1036
542
|
}
|
|
1037
543
|
}
|
|
1038
544
|
exports.VCard = VCard;
|
|
1039
|
-
/**
|
|
1040
|
-
* Mensaje de evento de calendario.
|
|
1041
|
-
* Calendar event message.
|
|
1042
|
-
*/
|
|
545
|
+
/** Mensaje de evento de calendario. / Calendar event message. */
|
|
1043
546
|
class Event extends Message {
|
|
1044
|
-
/** @internal */
|
|
1045
|
-
get _event() {
|
|
1046
|
-
return this._raw.raw.message?.eventMessage;
|
|
1047
|
-
}
|
|
547
|
+
/** @internal Bloque del evento en el raw. / Raw event block. */
|
|
548
|
+
get _event() { return this._raw.raw.message?.eventMessage; }
|
|
1048
549
|
/** Nombre del evento. / Event name. */
|
|
1049
|
-
get name() {
|
|
1050
|
-
return this._event?.name ?? '';
|
|
1051
|
-
}
|
|
550
|
+
get name() { return this._event?.name ?? ''; }
|
|
1052
551
|
/** Inicio en ISO UTC. / Start as ISO UTC. */
|
|
1053
|
-
get start() {
|
|
1054
|
-
return new Date(to_number(this._event?.startTime) * 1000).toISOString();
|
|
1055
|
-
}
|
|
552
|
+
get start() { return new Date(Number(this._event?.startTime?.toString() ?? 0) * 1_000).toISOString(); }
|
|
1056
553
|
/** Fin en ISO UTC, o null. / End as ISO UTC, or null. */
|
|
1057
|
-
get end() {
|
|
1058
|
-
const end = this._event?.endTime;
|
|
1059
|
-
return end == null ? null : new Date(to_number(end) * 1000).toISOString();
|
|
1060
|
-
}
|
|
554
|
+
get end() { return this._event?.endTime == null ? null : new Date(Number(this._event.endTime.toString()) * 1_000).toISOString(); }
|
|
1061
555
|
/** true si fue cancelado. / true when canceled. */
|
|
1062
|
-
get canceled() {
|
|
1063
|
-
return this._event?.isCanceled ?? false;
|
|
1064
|
-
}
|
|
556
|
+
get canceled() { return this._event?.isCanceled ?? false; }
|
|
1065
557
|
/** Link de unión, si aplica. / Join link, if any. */
|
|
1066
|
-
get link() {
|
|
1067
|
-
return this._event?.joinLink ?? '';
|
|
1068
|
-
}
|
|
558
|
+
get link() { return this._event?.joinLink ?? ''; }
|
|
1069
559
|
/** Ubicación del evento, o null. / Event location, or null. */
|
|
1070
560
|
get place() {
|
|
1071
561
|
const loc = this._event?.location;
|
|
@@ -1074,74 +564,96 @@ class Event extends Message {
|
|
|
1074
564
|
}
|
|
1075
565
|
exports.Event = Event;
|
|
1076
566
|
/**
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
1080
|
-
*
|
|
1081
|
-
* the persisted document or the raw baileys message — in that case the document is
|
|
1082
|
-
* derived right here (id, type, author, caption, mime, dates).
|
|
567
|
+
* Mensaje ligado a la sesión viva: la misma clase con los envíos, las lecturas, las acciones
|
|
568
|
+
* por id y las subclases para `instanceof`.
|
|
569
|
+
* Message bound to the live session: the same class with sends, reads, by-id actions and the
|
|
570
|
+
* subclasses for `instanceof`.
|
|
1083
571
|
*
|
|
1084
|
-
* @param
|
|
1085
|
-
* @
|
|
1086
|
-
* @returns Instancia del tipo correcto / Right-type instance
|
|
572
|
+
* @param init - Sesión activa: cliente, motor y socket / Active session: client, engine and socket
|
|
573
|
+
* @returns Clase `Message` con acceso a la sesión / `Message` class with session access
|
|
1087
574
|
*/
|
|
1088
|
-
function message(
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
575
|
+
function message(init) {
|
|
576
|
+
return class extends Message {
|
|
577
|
+
static { this.Text = Text; }
|
|
578
|
+
static { this.Image = Image; }
|
|
579
|
+
static { this.Video = Video; }
|
|
580
|
+
static { this.Audio = Audio; }
|
|
581
|
+
static { this.Sticker = Sticker; }
|
|
582
|
+
static { this.Document = Document; }
|
|
583
|
+
static { this.Location = Location; }
|
|
584
|
+
static { this.Poll = Poll; }
|
|
585
|
+
static { this.VCard = VCard; }
|
|
586
|
+
static { this.Event = Event; }
|
|
587
|
+
/**
|
|
588
|
+
* Mensaje por chat e id.
|
|
589
|
+
* Message by chat and id.
|
|
590
|
+
*
|
|
591
|
+
* @param cid - Teléfono, JID o LID del chat / Chat phone, JID or LID
|
|
592
|
+
* @param mid - Identificador del mensaje / Message identifier
|
|
593
|
+
*/
|
|
594
|
+
static async get(cid, mid) {
|
|
595
|
+
const jid = await (0, store_1.jid_of)(init.engine, cid, init.socket);
|
|
596
|
+
const doc = jid ? (0, store_1.deserialize)(await init.engine.get(`/chat/${jid}/message/${mid}`)) : null;
|
|
597
|
+
return doc ? new Message(init, doc) : null;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Pagina los mensajes del chat, del más reciente al más antiguo.
|
|
601
|
+
* Paginates chat messages, from the most recent to the oldest.
|
|
602
|
+
*
|
|
603
|
+
* @param cid - Teléfono, JID o LID del chat / Chat phone, JID or LID
|
|
604
|
+
* @param offset - Desplazamiento / Offset
|
|
605
|
+
* @param limit - Tamaño de página / Page size
|
|
606
|
+
*/
|
|
607
|
+
static async list(cid, offset = 0, limit = 50) {
|
|
608
|
+
const jid = await (0, store_1.jid_of)(init.engine, cid, init.socket);
|
|
609
|
+
return jid
|
|
610
|
+
? (await init.engine.list(`/chat/${jid}/message`, offset, limit))
|
|
611
|
+
.map((raw) => (0, store_1.deserialize)(raw))
|
|
612
|
+
.filter((doc) => doc !== null)
|
|
613
|
+
.map((doc) => new Message(init, doc))
|
|
614
|
+
: [];
|
|
615
|
+
}
|
|
616
|
+
/** Envía texto. / Sends text. */
|
|
617
|
+
static async text(cid, caption, extra = {}) { return send(init, cid, { text: caption }, undefined, extra); }
|
|
618
|
+
/** Envía imagen. / Sends an image. */
|
|
619
|
+
static async image(cid, buf, extra = {}) { return send(init, cid, { image: buf, caption: extra.caption }, buf, extra); }
|
|
620
|
+
/** Envía video. / Sends a video. */
|
|
621
|
+
static async video(cid, buf, extra = {}) { return send(init, cid, { video: buf, caption: extra.caption }, buf, extra); }
|
|
622
|
+
/** Envía audio. / Sends audio. */
|
|
623
|
+
static async audio(cid, buf, extra = {}) { return send(init, cid, { audio: buf, ptt: extra.ptt ?? true }, buf, extra); }
|
|
624
|
+
/** Envía ubicación. / Sends a location. */
|
|
625
|
+
static async location(cid, loc, extra = {}) { return send(init, cid, { location: { degreesLatitude: loc.lat, degreesLongitude: loc.lng } }, undefined, extra); }
|
|
626
|
+
/** Envía encuesta. / Sends a poll. */
|
|
627
|
+
static async poll(cid, input, extra = {}) {
|
|
628
|
+
return send(init, cid, poll_of(input, extra.multiple ?? false), undefined, extra, { multiple: extra.multiple ?? false });
|
|
629
|
+
}
|
|
630
|
+
/** Envía documento. / Sends a document. */
|
|
631
|
+
static async document(cid, buf, extra) {
|
|
632
|
+
return send(init, cid, { document: buf, fileName: extra.file_name, mimetype: extra.mimetype ?? 'application/octet-stream', caption: extra.caption }, buf, extra);
|
|
633
|
+
}
|
|
634
|
+
/** Envía tarjeta(s) de contacto. / Sends contact card(s). */
|
|
635
|
+
static async vcard(cid, contacts, extra = {}) {
|
|
636
|
+
const cards = vcards_of(contacts);
|
|
637
|
+
return send(init, cid, cards.content, cards.binary, extra);
|
|
638
|
+
}
|
|
639
|
+
/** Envía evento. / Sends an event. */
|
|
640
|
+
static async event(cid, data, extra = {}) {
|
|
641
|
+
const built = event_of(data);
|
|
642
|
+
return send(init, cid, built.content, built.binary, extra);
|
|
643
|
+
}
|
|
644
|
+
/** Reacciona a un mensaje por id. / Reacts to a message by id. */
|
|
645
|
+
static async react(cid, mid, emoji) { return (await this.get(cid, mid))?.react(emoji) ?? false; }
|
|
646
|
+
/** Destaca un mensaje por id. / Stars a message by id. */
|
|
647
|
+
static async star(cid, mid, value) { return (await this.get(cid, mid))?.star(value) ?? false; }
|
|
648
|
+
/** Marca un mensaje como leído por id. / Marks a message as read by id. */
|
|
649
|
+
static async seen(cid, mid) { return (await this.get(cid, mid))?.seen() ?? false; }
|
|
650
|
+
/** Edita un mensaje por id. / Edits a message by id. */
|
|
651
|
+
static async edit(cid, mid, caption) { return (await this.get(cid, mid))?.edit(caption) ?? false; }
|
|
652
|
+
/** Reenvía un mensaje por id. / Forwards a message by id. */
|
|
653
|
+
static async forward(cid, mid, target) { return (await this.get(cid, mid))?.forward(target) ?? false; }
|
|
654
|
+
/** Elimina un mensaje por id. / Deletes a message by id. */
|
|
655
|
+
static async delete(cid, mid, all = false) { return (await this.get(cid, mid))?.delete(all) ?? false; }
|
|
656
|
+
/** Reacciones de un mensaje por id. / Reactions of a message by id. */
|
|
657
|
+
static async reactions(cid, mid) { return (await this.get(cid, mid))?.reactions() ?? []; }
|
|
1145
658
|
};
|
|
1146
|
-
return new (types[doc.type] ?? Message)(wa, doc);
|
|
1147
659
|
}
|