@arcaelas/whatsapp 2.2.0 → 3.0.2

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 (127) hide show
  1. package/build/cjs/decorators.d.ts +9 -0
  2. package/build/cjs/decorators.js +26 -0
  3. package/build/cjs/decorators.js.map +1 -0
  4. package/build/cjs/index.d.ts +6 -10
  5. package/build/cjs/index.js +11 -10
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/lib/bot/decorator.d.ts +77 -0
  8. package/build/cjs/lib/bot/decorator.js +219 -0
  9. package/build/cjs/lib/bot/decorator.js.map +1 -0
  10. package/build/cjs/lib/bot/decorators.d.ts +113 -0
  11. package/build/cjs/lib/bot/decorators.js +253 -0
  12. package/build/cjs/lib/bot/decorators.js.map +1 -0
  13. package/build/cjs/lib/bot/index.d.ts +3 -0
  14. package/build/cjs/lib/bot/index.js +20 -0
  15. package/build/cjs/lib/bot/index.js.map +1 -0
  16. package/build/cjs/lib/chat/index.d.ts +227 -0
  17. package/build/cjs/lib/chat/index.js +324 -0
  18. package/build/cjs/lib/chat/index.js.map +1 -0
  19. package/build/cjs/lib/contact/index.d.ts +203 -0
  20. package/build/cjs/lib/contact/index.js +226 -0
  21. package/build/cjs/lib/contact/index.js.map +1 -0
  22. package/build/cjs/lib/message/index.d.ts +237 -0
  23. package/build/cjs/lib/message/index.js +685 -0
  24. package/build/cjs/lib/message/index.js.map +1 -0
  25. package/build/cjs/lib/store/engine/index.d.ts +34 -0
  26. package/build/cjs/lib/store/engine/index.js +13 -0
  27. package/build/cjs/lib/store/engine/index.js.map +1 -0
  28. package/build/cjs/lib/store/engine/lib/file_system/index.d.ts +56 -0
  29. package/build/cjs/lib/store/engine/lib/file_system/index.js +160 -0
  30. package/build/cjs/lib/store/engine/lib/file_system/index.js.map +1 -0
  31. package/build/cjs/lib/store/engine/lib/redis/index.d.ts +82 -0
  32. package/build/cjs/lib/store/engine/lib/redis/index.js +132 -0
  33. package/build/cjs/lib/store/engine/lib/redis/index.js.map +1 -0
  34. package/build/cjs/lib/store/index.d.ts +22 -0
  35. package/build/cjs/lib/store/index.js +38 -0
  36. package/build/cjs/lib/store/index.js.map +1 -0
  37. package/build/cjs/lib/whatsapp/index.d.ts +179 -0
  38. package/build/cjs/lib/whatsapp/index.js +754 -0
  39. package/build/cjs/lib/whatsapp/index.js.map +1 -0
  40. package/build/esm/decorators.d.ts +9 -0
  41. package/build/esm/decorators.js +9 -0
  42. package/build/esm/decorators.js.map +1 -0
  43. package/build/esm/index.d.ts +6 -10
  44. package/build/esm/index.js +4 -6
  45. package/build/esm/index.js.map +1 -1
  46. package/build/esm/lib/bot/decorator.d.ts +77 -0
  47. package/build/esm/lib/bot/decorator.js +210 -0
  48. package/build/esm/lib/bot/decorator.js.map +1 -0
  49. package/build/esm/lib/bot/decorators.d.ts +113 -0
  50. package/build/esm/lib/bot/decorators.js +242 -0
  51. package/build/esm/lib/bot/decorators.js.map +1 -0
  52. package/build/esm/lib/bot/index.d.ts +3 -0
  53. package/build/esm/lib/bot/index.js +3 -0
  54. package/build/esm/lib/bot/index.js.map +1 -0
  55. package/build/esm/lib/chat/index.d.ts +227 -0
  56. package/build/esm/lib/chat/index.js +319 -0
  57. package/build/esm/lib/chat/index.js.map +1 -0
  58. package/build/esm/lib/contact/index.d.ts +203 -0
  59. package/build/esm/lib/contact/index.js +221 -0
  60. package/build/esm/lib/contact/index.js.map +1 -0
  61. package/build/esm/lib/message/index.d.ts +237 -0
  62. package/build/esm/lib/message/index.js +673 -0
  63. package/build/esm/lib/message/index.js.map +1 -0
  64. package/build/esm/lib/store/engine/index.d.ts +34 -0
  65. package/build/esm/lib/store/engine/index.js +8 -0
  66. package/build/esm/lib/store/engine/index.js.map +1 -0
  67. package/build/esm/lib/store/engine/lib/file_system/index.d.ts +56 -0
  68. package/build/esm/lib/store/engine/lib/file_system/index.js +156 -0
  69. package/build/esm/lib/store/engine/lib/file_system/index.js.map +1 -0
  70. package/build/esm/lib/store/engine/lib/redis/index.d.ts +82 -0
  71. package/build/esm/lib/store/engine/lib/redis/index.js +128 -0
  72. package/build/esm/lib/store/engine/lib/redis/index.js.map +1 -0
  73. package/build/esm/lib/store/index.d.ts +22 -0
  74. package/build/esm/lib/store/index.js +31 -0
  75. package/build/esm/lib/store/index.js.map +1 -0
  76. package/build/esm/lib/whatsapp/index.d.ts +179 -0
  77. package/build/esm/lib/whatsapp/index.js +714 -0
  78. package/build/esm/lib/whatsapp/index.js.map +1 -0
  79. package/package.json +8 -6
  80. package/build/cjs/Chat.d.ts +0 -317
  81. package/build/cjs/Chat.js +0 -275
  82. package/build/cjs/Chat.js.map +0 -1
  83. package/build/cjs/Contact.d.ts +0 -1163
  84. package/build/cjs/Contact.js +0 -162
  85. package/build/cjs/Contact.js.map +0 -1
  86. package/build/cjs/Message.d.ts +0 -902
  87. package/build/cjs/Message.js +0 -515
  88. package/build/cjs/Message.js.map +0 -1
  89. package/build/cjs/WhatsApp.d.ts +0 -80
  90. package/build/cjs/WhatsApp.js +0 -412
  91. package/build/cjs/WhatsApp.js.map +0 -1
  92. package/build/cjs/store/driver/FileEngine.d.ts +0 -34
  93. package/build/cjs/store/driver/FileEngine.js +0 -86
  94. package/build/cjs/store/driver/FileEngine.js.map +0 -1
  95. package/build/cjs/store/driver/RedisEngine.d.ts +0 -47
  96. package/build/cjs/store/driver/RedisEngine.js +0 -70
  97. package/build/cjs/store/driver/RedisEngine.js.map +0 -1
  98. package/build/cjs/store/engine.d.ts +0 -53
  99. package/build/cjs/store/engine.js +0 -7
  100. package/build/cjs/store/engine.js.map +0 -1
  101. package/build/cjs/store/index.d.ts +0 -8
  102. package/build/cjs/store/index.js +0 -12
  103. package/build/cjs/store/index.js.map +0 -1
  104. package/build/esm/Chat.d.ts +0 -317
  105. package/build/esm/Chat.js +0 -270
  106. package/build/esm/Chat.js.map +0 -1
  107. package/build/esm/Contact.d.ts +0 -1163
  108. package/build/esm/Contact.js +0 -157
  109. package/build/esm/Contact.js.map +0 -1
  110. package/build/esm/Message.d.ts +0 -902
  111. package/build/esm/Message.js +0 -510
  112. package/build/esm/Message.js.map +0 -1
  113. package/build/esm/WhatsApp.d.ts +0 -80
  114. package/build/esm/WhatsApp.js +0 -372
  115. package/build/esm/WhatsApp.js.map +0 -1
  116. package/build/esm/store/driver/FileEngine.d.ts +0 -34
  117. package/build/esm/store/driver/FileEngine.js +0 -82
  118. package/build/esm/store/driver/FileEngine.js.map +0 -1
  119. package/build/esm/store/driver/RedisEngine.d.ts +0 -47
  120. package/build/esm/store/driver/RedisEngine.js +0 -66
  121. package/build/esm/store/driver/RedisEngine.js.map +0 -1
  122. package/build/esm/store/engine.d.ts +0 -53
  123. package/build/esm/store/engine.js +0 -6
  124. package/build/esm/store/engine.js.map +0 -1
  125. package/build/esm/store/index.d.ts +0 -8
  126. package/build/esm/store/index.js +0 -7
  127. package/build/esm/store/index.js.map +0 -1
@@ -0,0 +1,754 @@
1
+ "use strict";
2
+ /**
3
+ * @file whatsapp/index.ts
4
+ * @description Orquestador principal del cliente WhatsApp v3.
5
+ * Main orchestrator of the WhatsApp v3 client.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.WhatsApp = void 0;
45
+ const baileys_1 = require("baileys");
46
+ const node_events_1 = require("node:events");
47
+ const pino_1 = __importDefault(require("pino"));
48
+ const QRCode = __importStar(require("qrcode"));
49
+ const chat_1 = require("../../lib/chat");
50
+ const contact_1 = require("../../lib/contact");
51
+ const message_1 = require("../../lib/message");
52
+ const store_1 = require("../../lib/store");
53
+ /**
54
+ * Cliente principal de WhatsApp. No inicia la conexión al instanciar.
55
+ * Main WhatsApp client. Does not connect on instantiation.
56
+ *
57
+ * @example
58
+ * const wa = new WhatsApp({ engine: new FileSystemEngine(__dirname), phone: 584144709840 });
59
+ * wa.on('message:created', (msg) => console.log(msg.caption));
60
+ * await wa.connect((code) => console.log(code));
61
+ */
62
+ class WhatsApp {
63
+ constructor(options) {
64
+ /** @internal */
65
+ this._socket = null;
66
+ this._intentional_close = false;
67
+ this._has_connected = false;
68
+ this._retry_timer = null;
69
+ this._retry_count = 0;
70
+ this.engine = options.engine;
71
+ this._phone =
72
+ options.phone !== undefined ? String(options.phone).replace(/\D+/g, '') : undefined;
73
+ this._autoclean = options.autoclean ?? true;
74
+ this._sync = options.sync ?? false;
75
+ this._reconnect = this._parse_reconnect(options.reconnect);
76
+ this._event = new node_events_1.EventEmitter();
77
+ this.Contact = (0, contact_1.contact)(this);
78
+ this.Chat = (0, chat_1.chat)(this);
79
+ this.Message = (0, message_1.message)(this);
80
+ }
81
+ /** @internal */
82
+ _parse_reconnect(option) {
83
+ if (option === false) {
84
+ return { max: 0, interval_ms: 60_000 };
85
+ }
86
+ if (option === undefined || option === true) {
87
+ return { max: null, interval_ms: 60_000 };
88
+ }
89
+ if (typeof option === 'number') {
90
+ return { max: option, interval_ms: 60_000 };
91
+ }
92
+ return {
93
+ max: option.max ?? null,
94
+ interval_ms: (option.interval ?? 60) * 1000,
95
+ };
96
+ }
97
+ /**
98
+ * Registra un listener de evento. Retorna función para desuscribirse.
99
+ * Registers an event listener. Returns an unsubscribe function.
100
+ */
101
+ on(event, handler) {
102
+ this._event.on(event, handler);
103
+ return () => { this._event.off(event, handler); };
104
+ }
105
+ /**
106
+ * Quita un listener previamente registrado.
107
+ * Removes a previously registered listener.
108
+ */
109
+ off(event, handler) {
110
+ this._event.off(event, handler);
111
+ return this;
112
+ }
113
+ /**
114
+ * Registra un listener one-shot. Retorna función para desuscribirse antes de que dispare.
115
+ * Registers a one-shot listener. Returns an unsubscribe function.
116
+ */
117
+ once(event, handler) {
118
+ this._event.once(event, handler);
119
+ return () => { this._event.off(event, handler); };
120
+ }
121
+ /**
122
+ * @internal
123
+ * Normaliza cualquier identificador (JID, LID, número, etc.) a JID canónico.
124
+ * Uso interno de la librería — no forma parte de la API pública.
125
+ */
126
+ async _resolve_jid(uid) {
127
+ let result = null;
128
+ if (uid.endsWith('@g.us') || uid.endsWith('@s.whatsapp.net')) {
129
+ result = uid;
130
+ }
131
+ else if (uid.endsWith('@lid')) {
132
+ const direct = (0, store_1.deserialize)(await this.engine.get(`/lid/${uid}`));
133
+ if (direct) {
134
+ result = direct.includes('@') ? direct : `${direct}@s.whatsapp.net`;
135
+ }
136
+ else {
137
+ const reverse = (0, store_1.deserialize)(await this.engine.get(`/lid/${uid.split('@')[0]}_reverse`));
138
+ if (reverse != null) {
139
+ result = `${reverse}@s.whatsapp.net`;
140
+ }
141
+ }
142
+ }
143
+ else {
144
+ const cleaned = uid.replace(/\D/g, '');
145
+ if (cleaned) {
146
+ result = `${cleaned}@s.whatsapp.net`;
147
+ }
148
+ }
149
+ return result;
150
+ }
151
+ /**
152
+ * Inicia la conexión. El callback recibe el PIN (string) si se configuró `phone`, o el QR (Buffer PNG) si no.
153
+ * Resuelve cuando la sesión sincroniza; reintenta automáticamente en cierres no-loggedOut.
154
+ *
155
+ * Starts the connection. Callback receives the PIN (string) when `phone` is configured, or the QR (PNG Buffer) otherwise.
156
+ * Resolves once the session is synced; retries on non-loggedOut disconnects.
157
+ */
158
+ async connect(callback) {
159
+ const { version } = await (0, baileys_1.fetchLatestBaileysVersion)();
160
+ this._intentional_close = false;
161
+ this._has_connected = false;
162
+ return new Promise((resolve, reject) => {
163
+ const start = async () => {
164
+ // Re-lee creds en cada start() para que limpiezas del engine tomen efecto
165
+ // en reintentos (permite al consumer forzar nueva sesión borrando /session/creds).
166
+ const stored = await this.engine.get('/session/creds');
167
+ const creds = (0, store_1.deserialize)(stored) ?? (0, baileys_1.initAuthCreds)();
168
+ this._socket = (0, baileys_1.makeWASocket)({
169
+ version,
170
+ auth: {
171
+ creds,
172
+ keys: {
173
+ get: async (type, ids) => {
174
+ const data = {};
175
+ for (const id of ids) {
176
+ const value = (0, store_1.deserialize)(await this.engine.get(`/session/${type}/${id}`));
177
+ if (value) {
178
+ data[id] =
179
+ type === 'app-state-sync-key'
180
+ ? baileys_1.proto.Message.AppStateSyncKeyData.create(value)
181
+ : value;
182
+ }
183
+ }
184
+ return data;
185
+ },
186
+ set: async (data) => {
187
+ for (const category in data) {
188
+ for (const id in data[category]) {
189
+ const value = data[category][id];
190
+ if (value != null) {
191
+ await this.engine.set(`/session/${category}/${id}`, (0, store_1.serialize)(value));
192
+ }
193
+ else {
194
+ await this.engine.unset(`/session/${category}/${id}`);
195
+ }
196
+ }
197
+ }
198
+ },
199
+ },
200
+ },
201
+ browser: baileys_1.Browsers.windows('Chrome'),
202
+ printQRInTerminal: false,
203
+ logger: (0, pino_1.default)({ level: 'silent' }),
204
+ syncFullHistory: this._sync,
205
+ markOnlineOnConnect: false,
206
+ });
207
+ const socket = this._socket;
208
+ socket.ev.on('creds.update', () => this.engine.set('/session/creds', (0, store_1.serialize)(creds)));
209
+ socket.ev.on('connection.update', async (update) => {
210
+ const { connection, lastDisconnect, qr } = update;
211
+ if (qr && !creds.registered) {
212
+ // Baileys refresca QR periódicamente (~20s). Emitimos nuevo pair
213
+ // code / QR en cada refresh para que el usuario pueda renovar si
214
+ // el anterior expiró.
215
+ if (this._phone) {
216
+ await callback(await socket.requestPairingCode(this._phone));
217
+ }
218
+ else {
219
+ await callback(await QRCode.toBuffer(qr, { type: 'png', margin: 2 }));
220
+ }
221
+ }
222
+ if (connection === 'open') {
223
+ this._has_connected = true;
224
+ this._retry_count = 0;
225
+ this._event.emit('connected', this);
226
+ resolve();
227
+ }
228
+ else if (connection === 'close') {
229
+ this._socket = null;
230
+ const status_code = lastDisconnect?.error?.output?.statusCode;
231
+ // `restartRequired` (515) es una reconexión exigida por el protocolo
232
+ // tras el sync inicial — no es un disconnect "real".
233
+ const is_transient = status_code === baileys_1.DisconnectReason.restartRequired;
234
+ // Limpieza del engine ANTES de emitir `disconnected` para que los
235
+ // listeners vean el estado final (engine vaciado o creds borradas).
236
+ if (status_code === baileys_1.DisconnectReason.loggedOut) {
237
+ if (this._autoclean) {
238
+ await this.engine.clear();
239
+ }
240
+ else {
241
+ await this.engine.unset('/session/creds');
242
+ }
243
+ }
244
+ if (this._has_connected && !is_transient) {
245
+ this._event.emit('disconnected', this);
246
+ }
247
+ if (!this._intentional_close) {
248
+ if (status_code === baileys_1.DisconnectReason.loggedOut) {
249
+ reject(new Error('Logged out'));
250
+ }
251
+ else {
252
+ const max = this._reconnect.max;
253
+ // Transient closes (restartRequired) son parte del protocolo,
254
+ // no cuentan contra el límite de reintentos por fallo.
255
+ const exhausted = !is_transient && max !== null && this._retry_count >= max;
256
+ if (exhausted) {
257
+ reject(new Error(`Reconnect attempts exhausted (${max})`));
258
+ }
259
+ else {
260
+ if (!is_transient) {
261
+ this._retry_count++;
262
+ }
263
+ const delay = is_transient ? 0 : this._reconnect.interval_ms;
264
+ this._retry_timer = setTimeout(() => {
265
+ this._retry_timer = null;
266
+ start().catch(reject);
267
+ }, delay);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ });
273
+ this._attach_business_handlers(socket);
274
+ };
275
+ start().catch(reject);
276
+ });
277
+ }
278
+ /**
279
+ * Cierra la conexión. Con `destroy: true` vacía el engine completo.
280
+ * Closes the connection. With `destroy: true` clears the engine entirely.
281
+ */
282
+ async disconnect(options = {}) {
283
+ this._intentional_close = true;
284
+ // Cancela cualquier retry programado por un close anterior, para no resucitar
285
+ // el socket después de una desconexión manual.
286
+ if (this._retry_timer) {
287
+ clearTimeout(this._retry_timer);
288
+ this._retry_timer = null;
289
+ }
290
+ if (this._socket) {
291
+ try {
292
+ // Pasa un error Boom-like con statusCode=connectionClosed (428) para que
293
+ // `lastDisconnect.error.output.statusCode` quede explícito en el close
294
+ // en lugar de `undefined`.
295
+ const intentional = Object.assign(new Error('intentional close'), {
296
+ output: { statusCode: baileys_1.DisconnectReason.connectionClosed },
297
+ });
298
+ this._socket.end(intentional);
299
+ }
300
+ catch {
301
+ /* socket may already be closed */
302
+ }
303
+ this._socket = null;
304
+ }
305
+ if (options.destroy) {
306
+ await this.engine.clear();
307
+ }
308
+ void options.silent;
309
+ }
310
+ /**
311
+ * Conecta los handlers de eventos de baileys: contactos, chats y mensajes.
312
+ * Wires baileys event handlers: contacts, chats and messages.
313
+ *
314
+ * @internal
315
+ */
316
+ _attach_business_handlers(socket) {
317
+ socket.ev.on('messaging-history.set', async ({ chats, contacts, messages }) => {
318
+ await this._handle_contacts_upsert(contacts);
319
+ await this._handle_chats_upsert(chats);
320
+ await this._handle_messages_upsert(messages);
321
+ });
322
+ socket.ev.on('contacts.upsert', (contacts) => {
323
+ void this._handle_contacts_upsert(contacts);
324
+ });
325
+ socket.ev.on('contacts.update', (contacts) => {
326
+ void this._handle_contacts_update(contacts);
327
+ });
328
+ socket.ev.on('contacts.delete', (ids) => { void this._handle_contacts_delete(ids); });
329
+ socket.ev.on('lid-mapping.update', ({ lid, pn }) => {
330
+ void this._handle_lid_mapping(lid, pn);
331
+ });
332
+ socket.ev.on('chats.upsert', (chats) => {
333
+ void this._handle_chats_upsert(chats);
334
+ });
335
+ socket.ev.on('chats.update', (chats) => {
336
+ void this._handle_chats_update(chats);
337
+ });
338
+ socket.ev.on('chats.delete', (ids) => {
339
+ void this._handle_chats_delete(ids);
340
+ });
341
+ socket.ev.on('messages.upsert', ({ messages }) => {
342
+ void this._handle_messages_upsert(messages);
343
+ });
344
+ socket.ev.on('messages.update', (updates) => {
345
+ void this._handle_messages_update(updates);
346
+ });
347
+ socket.ev.on('message-receipt.update', (updates) => {
348
+ void this._handle_message_receipt(updates);
349
+ });
350
+ socket.ev.on('messages.reaction', (reactions) => {
351
+ void this._handle_messages_reaction(reactions);
352
+ });
353
+ }
354
+ /** @internal */
355
+ async _handle_contacts_upsert(contacts) {
356
+ for (const c of contacts) {
357
+ if (c.id) {
358
+ const existing = await this.engine.get(`/contact/${c.id}`);
359
+ const raw = {
360
+ id: c.id,
361
+ lid: c.lid ?? null,
362
+ name: c.name ?? null,
363
+ notify: c.notify ?? null,
364
+ verified_name: c.verifiedName ?? null,
365
+ img_url: c.imgUrl ?? null,
366
+ status: c.status ?? null,
367
+ };
368
+ await this.engine.set(`/contact/${c.id}`, (0, store_1.serialize)(raw));
369
+ if (raw.lid) {
370
+ await this.engine.set(`/lid/${raw.lid}`, (0, store_1.serialize)(raw.id));
371
+ }
372
+ if (existing === null) {
373
+ const cached_chat = (0, store_1.deserialize)(await this.engine.get(`/chat/${raw.id}`));
374
+ const chat_instance = new this.Chat(cached_chat ?? { id: raw.id, name: raw.name ?? raw.notify ?? raw.id.split('@')[0] });
375
+ this._event.emit('contact:created', new this.Contact(raw, chat_instance), chat_instance, this);
376
+ }
377
+ }
378
+ }
379
+ }
380
+ /** @internal */
381
+ async _handle_contacts_update(contacts) {
382
+ for (const c of contacts) {
383
+ if (c.id) {
384
+ const current = (0, store_1.deserialize)(await this.engine.get(`/contact/${c.id}`));
385
+ if (current) {
386
+ const patch = {};
387
+ if (c.notify) {
388
+ patch.notify = c.notify;
389
+ }
390
+ if (c.name) {
391
+ patch.name = c.name;
392
+ }
393
+ if (c.imgUrl) {
394
+ patch.img_url = c.imgUrl;
395
+ }
396
+ if (c.status) {
397
+ patch.status = c.status;
398
+ }
399
+ if (c.lid) {
400
+ patch.lid = c.lid;
401
+ }
402
+ if (Object.keys(patch).length > 0) {
403
+ const merged = { ...current, ...patch };
404
+ await this.engine.set(`/contact/${c.id}`, (0, store_1.serialize)(merged));
405
+ if (patch.lid) {
406
+ await this.engine.set(`/lid/${patch.lid}`, (0, store_1.serialize)(c.id));
407
+ }
408
+ const cached_chat = (0, store_1.deserialize)(await this.engine.get(`/chat/${c.id}`));
409
+ const chat_instance = new this.Chat(cached_chat ?? { id: c.id, name: merged.name ?? merged.notify ?? c.id.split('@')[0] });
410
+ this._event.emit('contact:updated', new this.Contact(merged, chat_instance), chat_instance, this);
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ /** @internal */
417
+ async _handle_lid_mapping(lid, pn) {
418
+ await this.engine.set(`/lid/${lid}`, (0, store_1.serialize)(pn));
419
+ await this.engine.set(`/lid/${pn}`, (0, store_1.serialize)(lid));
420
+ }
421
+ /** @internal */
422
+ async _handle_chats_upsert(chats) {
423
+ for (const ch of chats) {
424
+ if (ch.id) {
425
+ const current = (0, store_1.deserialize)(await this.engine.get(`/chat/${ch.id}`));
426
+ const raw = current ?? {
427
+ id: ch.id,
428
+ name: ch.name ?? null,
429
+ archived: ch.archived ?? null,
430
+ pinned: ch.pinned ?? null,
431
+ mute_end_time: ch.muteEndTime != null ? Number(ch.muteEndTime) : null,
432
+ unread_count: ch.unreadCount ?? null,
433
+ read_only: ch.readOnly ?? null,
434
+ };
435
+ if (ch.name) {
436
+ raw.name = ch.name;
437
+ }
438
+ await this.engine.set(`/chat/${ch.id}`, (0, store_1.serialize)(raw));
439
+ if (current === null) {
440
+ this._event.emit('chat:created', new this.Chat(raw), this);
441
+ }
442
+ }
443
+ }
444
+ }
445
+ /** @internal */
446
+ async _handle_chats_update(chats) {
447
+ for (const ch of chats) {
448
+ if (ch.id) {
449
+ const current = (0, store_1.deserialize)(await this.engine.get(`/chat/${ch.id}`)) ?? {
450
+ id: ch.id,
451
+ name: ch.name ?? null,
452
+ };
453
+ const patch = {};
454
+ const pinned_changed = 'pinned' in ch;
455
+ const archived_changed = ch.archived !== undefined;
456
+ const mute_changed = 'muteEndTime' in ch;
457
+ if (ch.name) {
458
+ patch.name = ch.name;
459
+ }
460
+ if (pinned_changed) {
461
+ patch.pinned = ch.pinned ?? null;
462
+ }
463
+ if (archived_changed) {
464
+ patch.archived = ch.archived ?? false;
465
+ }
466
+ if (mute_changed) {
467
+ patch.mute_end_time = ch.muteEndTime != null ? Number(ch.muteEndTime) : null;
468
+ }
469
+ if (ch.unreadCount != null) {
470
+ patch.unread_count = ch.unreadCount;
471
+ }
472
+ if (Object.keys(patch).length > 0) {
473
+ const merged = { ...current, ...patch };
474
+ await this.engine.set(`/chat/${ch.id}`, (0, store_1.serialize)(merged));
475
+ if (pinned_changed) {
476
+ this._event.emit(ch.pinned != null ? 'chat:pinned' : 'chat:unpinned', new this.Chat(merged), this);
477
+ }
478
+ if (archived_changed) {
479
+ this._event.emit(ch.archived ? 'chat:archived' : 'chat:unarchived', new this.Chat(merged), this);
480
+ }
481
+ if (mute_changed) {
482
+ const is_muted = patch.mute_end_time != null && patch.mute_end_time > Date.now();
483
+ this._event.emit(is_muted ? 'chat:muted' : 'chat:unmuted', new this.Chat(merged), this);
484
+ }
485
+ }
486
+ }
487
+ }
488
+ }
489
+ /** @internal */
490
+ async _handle_chats_delete(ids) {
491
+ for (const cid of ids) {
492
+ const raw = (0, store_1.deserialize)(await this.engine.get(`/chat/${cid}`)) ?? { id: cid };
493
+ await this.engine.unset(`/chat/${cid}`);
494
+ this._event.emit('chat:deleted', new this.Chat(raw), this);
495
+ }
496
+ }
497
+ /** @internal */
498
+ async _handle_contacts_delete(ids) {
499
+ for (const id of ids) {
500
+ const raw = (0, store_1.deserialize)(await this.engine.get(`/contact/${id}`));
501
+ await this.engine.unset(`/contact/${id}`);
502
+ if (raw) {
503
+ const cached_chat = (0, store_1.deserialize)(await this.engine.get(`/chat/${id}`));
504
+ const chat_instance = new this.Chat(cached_chat ?? { id, name: raw.name ?? raw.notify ?? id.split('@')[0] });
505
+ this._event.emit('contact:deleted', new this.Contact(raw, chat_instance), chat_instance, this);
506
+ }
507
+ }
508
+ }
509
+ /** @internal */
510
+ async _handle_message_receipt(updates) {
511
+ for (const { key, receipt } of updates) {
512
+ if (key.remoteJid && key.id && (receipt.readTimestamp != null || receipt.playedTimestamp != null)) {
513
+ const doc = (0, store_1.deserialize)(await this.engine.get(`/chat/${key.remoteJid}/message/${key.id}`));
514
+ if (doc) {
515
+ const msg_instance = await this.Message.build_instance(doc);
516
+ this._event.emit('message:seen', msg_instance, await msg_instance.chat(), this);
517
+ }
518
+ }
519
+ }
520
+ }
521
+ /** @internal */
522
+ async _handle_messages_upsert(messages) {
523
+ for (const msg of messages) {
524
+ if (msg.key?.remoteJid && msg.key.id) {
525
+ const cid = msg.key.remoteJidAlt ?? msg.key.remoteJid;
526
+ const mid = msg.key.id;
527
+ const content_type = (0, baileys_1.getContentType)(msg.message ?? {});
528
+ if (content_type === 'reactionMessage') {
529
+ continue;
530
+ }
531
+ if (content_type === 'pollUpdateMessage') {
532
+ const update = msg.message?.pollUpdateMessage;
533
+ const creation_key = update?.pollCreationMessageKey;
534
+ if (creation_key?.id &&
535
+ creation_key.remoteJid &&
536
+ update?.vote?.encPayload &&
537
+ update.vote.encIv) {
538
+ const resolved_cid = (await this._resolve_jid(creation_key.remoteJid)) ?? creation_key.remoteJid;
539
+ const target_mid = creation_key.id;
540
+ const poll_doc = (0, store_1.deserialize)(await this.engine.get(`/chat/${resolved_cid}/message/${target_mid}`));
541
+ const secret_raw = poll_doc?.raw.message?.messageContextInfo?.messageSecret;
542
+ const message_secret = typeof secret_raw === 'string' ? Buffer.from(secret_raw, 'base64') : secret_raw;
543
+ if (poll_doc && message_secret) {
544
+ try {
545
+ const poll_key = poll_doc.raw.key ?? {};
546
+ // Modo LID: si la conversación usa addressing LID, usar LIDs en el HMAC
547
+ const use_lid = msg.key.addressingMode === 'lid' ||
548
+ msg.key.remoteJid?.endsWith('@lid') === true;
549
+ const self_id = this._socket?.user?.id ?? '';
550
+ const self_lid = this._socket?.user?.lid ?? '';
551
+ const voter_jid = use_lid
552
+ ? (msg.key.remoteJid ?? '')
553
+ : msg.key.participant ||
554
+ msg.key.remoteJidAlt ||
555
+ msg.key.remoteJid ||
556
+ '';
557
+ const poll_creator_jid = poll_key.fromMe
558
+ ? use_lid
559
+ ? self_lid
560
+ : self_id
561
+ : use_lid
562
+ ? (poll_key.remoteJid ?? '')
563
+ : poll_key.participant ||
564
+ poll_key.remoteJidAlt ||
565
+ poll_key.remoteJid ||
566
+ '';
567
+ const decrypted = (0, baileys_1.decryptPollVote)({ encPayload: update.vote.encPayload, encIv: update.vote.encIv }, {
568
+ pollCreatorJid: poll_creator_jid,
569
+ pollMsgId: target_mid,
570
+ pollEncKey: message_secret,
571
+ voterJid: voter_jid,
572
+ });
573
+ (0, baileys_1.updateMessageWithPollUpdate)(poll_doc.raw, {
574
+ pollUpdateMessageKey: msg.key,
575
+ vote: decrypted,
576
+ senderTimestampMs: Number(msg.messageTimestamp) || Date.now(),
577
+ });
578
+ await this.engine.set(`/chat/${resolved_cid}/message/${target_mid}`, (0, store_1.serialize)(poll_doc));
579
+ const msg_instance = await this.Message.build_instance(poll_doc);
580
+ this._event.emit('message:updated', msg_instance, await msg_instance.chat(), this);
581
+ }
582
+ catch {
583
+ /* decrypt may fail */
584
+ }
585
+ }
586
+ }
587
+ continue;
588
+ }
589
+ if (content_type === 'protocolMessage') {
590
+ const protocol = msg.message?.protocolMessage;
591
+ if (protocol?.key?.id) {
592
+ const target_mid = protocol.key.id;
593
+ const target_cid = protocol.key.remoteJid ?? cid;
594
+ const doc = (0, store_1.deserialize)(await this.engine.get(`/chat/${target_cid}/message/${target_mid}`));
595
+ if (protocol.type === baileys_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT &&
596
+ protocol.editedMessage &&
597
+ doc) {
598
+ doc.raw.message = protocol.editedMessage;
599
+ doc.edited = true;
600
+ doc.caption = this.Message.build_message_doc(doc.raw, this._socket?.user?.id, true).caption;
601
+ await this.engine.set(`/chat/${target_cid}/message/${target_mid}`, (0, store_1.serialize)(doc));
602
+ const msg_instance = await this.Message.build_instance(doc);
603
+ this._event.emit('message:updated', msg_instance, await msg_instance.chat(), this);
604
+ }
605
+ else if (protocol.type === baileys_1.proto.Message.ProtocolMessage.Type.REVOKE) {
606
+ await this.engine.unset(`/chat/${target_cid}/message/${target_mid}`);
607
+ if (doc) {
608
+ const msg_instance = await this.Message.build_instance(doc);
609
+ this._event.emit('message:deleted', msg_instance, await msg_instance.chat(), this);
610
+ }
611
+ }
612
+ }
613
+ continue;
614
+ }
615
+ const doc = this.Message.build_message_doc(msg, this._socket?.user?.id);
616
+ // Autocreación de contacto/chat desde pushName cuando baileys no emite upsert previo
617
+ if (!doc.me) {
618
+ const push_name = msg.pushName ?? null;
619
+ const is_group = cid.endsWith('@g.us');
620
+ if (doc.author && !(await this.engine.get(`/contact/${doc.author}`))) {
621
+ const lid_key = msg.key.remoteJid?.endsWith('@lid') ? msg.key.remoteJid : null;
622
+ const contact_raw = {
623
+ id: doc.author,
624
+ lid: lid_key,
625
+ name: null,
626
+ notify: is_group ? null : push_name,
627
+ verified_name: msg.verifiedBizName ?? null,
628
+ img_url: null,
629
+ status: null,
630
+ };
631
+ await this.engine.set(`/contact/${doc.author}`, (0, store_1.serialize)(contact_raw));
632
+ if (lid_key) {
633
+ await this.engine.set(`/lid/${lid_key}`, (0, store_1.serialize)(doc.author));
634
+ }
635
+ const cached_chat = (0, store_1.deserialize)(await this.engine.get(`/chat/${doc.author}`));
636
+ const author_chat = new this.Chat(cached_chat ?? { id: doc.author, name: push_name ?? doc.author.split('@')[0] });
637
+ this._event.emit('contact:created', new this.Contact(contact_raw, author_chat), author_chat, this);
638
+ }
639
+ if (!(await this.engine.get(`/chat/${cid}`))) {
640
+ const chat_raw = {
641
+ id: cid,
642
+ name: is_group ? null : push_name,
643
+ };
644
+ await this.engine.set(`/chat/${cid}`, (0, store_1.serialize)(chat_raw));
645
+ this._event.emit('chat:created', new this.Chat(chat_raw), this);
646
+ }
647
+ }
648
+ await this.engine.set(`/chat/${cid}/message/${mid}`, (0, store_1.serialize)(doc));
649
+ let content_buf = Buffer.alloc(0);
650
+ if (doc.type === 'text') {
651
+ content_buf = Buffer.from(doc.caption, 'utf-8');
652
+ }
653
+ else if (doc.type === 'location') {
654
+ const loc = msg.message?.locationMessage ?? msg.message?.liveLocationMessage;
655
+ content_buf = Buffer.from(JSON.stringify({ lat: loc?.degreesLatitude, lng: loc?.degreesLongitude }), 'utf-8');
656
+ }
657
+ else if (doc.type === 'poll') {
658
+ const poll = msg.message?.pollCreationMessage ??
659
+ msg.message?.pollCreationMessageV2 ??
660
+ msg.message?.pollCreationMessageV3;
661
+ content_buf = Buffer.from(JSON.stringify({
662
+ content: poll?.name ?? '',
663
+ options: poll?.options?.map((o) => ({ content: o.optionName })) ?? [],
664
+ }), 'utf-8');
665
+ }
666
+ else if (this._socket && ['image', 'video', 'audio'].includes(doc.type)) {
667
+ try {
668
+ const buffer = await (0, baileys_1.downloadMediaMessage)(msg, 'buffer', {});
669
+ if (Buffer.isBuffer(buffer)) {
670
+ content_buf = buffer;
671
+ }
672
+ }
673
+ catch {
674
+ /* media download may fail */
675
+ }
676
+ }
677
+ if (content_buf.length > 0) {
678
+ await this.engine.set(`/chat/${cid}/message/${mid}/content`, (0, store_1.serialize)({ data: content_buf.toString('base64') }));
679
+ }
680
+ const instance = await this.Message.build_instance(doc);
681
+ const chat_instance = await instance.chat();
682
+ this._event.emit('message:created', instance, chat_instance, this);
683
+ if (doc.forwarded) {
684
+ this._event.emit('message:forwarded', instance, chat_instance, this);
685
+ }
686
+ }
687
+ }
688
+ }
689
+ /** @internal */
690
+ async _handle_messages_update(updates) {
691
+ for (const { key, update: upd } of updates) {
692
+ if (key.remoteJid && key.id) {
693
+ const doc = (0, store_1.deserialize)(await this.engine.get(`/chat/${key.remoteJid}/message/${key.id}`));
694
+ if (doc) {
695
+ const raw = doc.raw ?? { key };
696
+ const upd_any = upd;
697
+ const edited_message = upd_any.message?.editedMessage?.message;
698
+ const content_update = upd_any.message;
699
+ const status = upd_any.status;
700
+ const starred_changed = upd_any.starred !== undefined;
701
+ if (edited_message) {
702
+ raw.message = edited_message;
703
+ doc.raw = raw;
704
+ doc.edited = true;
705
+ doc.caption = this.Message.build_message_doc(raw, this._socket?.user?.id, true).caption;
706
+ await this.engine.set(`/chat/${key.remoteJid}/message/${key.id}`, (0, store_1.serialize)(doc));
707
+ const msg_instance = await this.Message.build_instance(doc);
708
+ this._event.emit('message:updated', msg_instance, await msg_instance.chat(), this);
709
+ }
710
+ else if (content_update) {
711
+ // Actualización de contenido (ej: live location). Mergea sobre el raw existente.
712
+ raw.message = { ...raw.message, ...content_update };
713
+ doc.raw = raw;
714
+ doc.caption = this.Message.build_message_doc(raw, this._socket?.user?.id, doc.edited).caption;
715
+ await this.engine.set(`/chat/${key.remoteJid}/message/${key.id}`, (0, store_1.serialize)(doc));
716
+ const msg_instance = await this.Message.build_instance(doc);
717
+ this._event.emit('message:updated', msg_instance, await msg_instance.chat(), this);
718
+ }
719
+ else if (starred_changed) {
720
+ doc.starred = upd_any.starred === true;
721
+ raw.starred = doc.starred;
722
+ doc.raw = raw;
723
+ await this.engine.set(`/chat/${key.remoteJid}/message/${key.id}`, (0, store_1.serialize)(doc));
724
+ const msg_instance = await this.Message.build_instance(doc);
725
+ this._event.emit(doc.starred ? 'message:starred' : 'message:unstarred', msg_instance, await msg_instance.chat(), this);
726
+ }
727
+ else if (status !== undefined) {
728
+ raw.status = status;
729
+ doc.status = status;
730
+ doc.raw = raw;
731
+ await this.engine.set(`/chat/${key.remoteJid}/message/${key.id}`, (0, store_1.serialize)(doc));
732
+ const msg_instance = await this.Message.build_instance(doc);
733
+ this._event.emit('message:updated', msg_instance, await msg_instance.chat(), this);
734
+ }
735
+ }
736
+ }
737
+ }
738
+ }
739
+ /** @internal */
740
+ async _handle_messages_reaction(reactions) {
741
+ for (const { key, reaction } of reactions) {
742
+ if (key.remoteJid && key.id) {
743
+ const doc = (0, store_1.deserialize)(await this.engine.get(`/chat/${key.remoteJid}/message/${key.id}`));
744
+ if (doc) {
745
+ const msg_instance = await this.Message.build_instance(doc);
746
+ this._event.emit('message:reacted', msg_instance, await msg_instance.chat(), reaction.text ?? '', this);
747
+ }
748
+ }
749
+ }
750
+ }
751
+ }
752
+ exports.WhatsApp = WhatsApp;
753
+ exports.default = WhatsApp;
754
+ //# sourceMappingURL=index.js.map