miaw-core 1.0.0 → 1.1.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.
@@ -1,53 +1,16 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.MiawClient = void 0;
40
- const baileys_1 = __importStar(require("@whiskeysockets/baileys"));
41
- const events_1 = require("events");
42
- const pino_1 = __importDefault(require("pino"));
43
- const path = __importStar(require("path"));
44
- const AuthHandler_1 = require("../handlers/AuthHandler");
45
- const MessageHandler_1 = require("../handlers/MessageHandler");
1
+ import makeWASocket, { DisconnectReason, fetchLatestBaileysVersion, makeCacheableSignalKeyStore, downloadMediaMessage, } from "@whiskeysockets/baileys";
2
+ import { EventEmitter } from "node:events";
3
+ import pino from "pino";
4
+ import * as path from "node:path";
5
+ import { AuthHandler } from "../handlers/AuthHandler.js";
6
+ import { MessageHandler } from "../handlers/MessageHandler.js";
46
7
  /**
47
8
  * LRU Cache for LID to JID mappings
48
9
  * Prevents unbounded memory growth while maintaining frequently used mappings
49
10
  */
50
11
  class LruCache {
12
+ cache;
13
+ maxSize;
51
14
  constructor(maxSize = 1000) {
52
15
  this.cache = new Map();
53
16
  this.maxSize = maxSize;
@@ -89,18 +52,26 @@ class LruCache {
89
52
  /**
90
53
  * Main client class for interacting with WhatsApp
91
54
  */
92
- class MiawClient extends events_1.EventEmitter {
55
+ export class MiawClient extends EventEmitter {
56
+ options;
57
+ socket = null;
58
+ authHandler;
59
+ connectionState = "disconnected";
60
+ reconnectAttempts = 0;
61
+ reconnectTimer = null;
62
+ logger;
63
+ lidToJidMap = new LruCache(1000);
64
+ // In-memory stores for v0.9.0
65
+ contactsStore = new Map();
66
+ labelsStore = new Map();
67
+ messagesStore = new Map(); // JID -> messages
68
+ chatsStore = new Map(); // JID -> chat info
93
69
  constructor(options) {
94
70
  super();
95
- this.socket = null;
96
- this.connectionState = 'disconnected';
97
- this.reconnectAttempts = 0;
98
- this.reconnectTimer = null;
99
- this.lidToJidMap = new LruCache(1000);
100
71
  // Set default options
101
72
  this.options = {
102
73
  instanceId: options.instanceId,
103
- sessionPath: options.sessionPath || './sessions',
74
+ sessionPath: options.sessionPath || "./sessions",
104
75
  debug: options.debug || false,
105
76
  logger: options.logger,
106
77
  autoReconnect: options.autoReconnect !== false,
@@ -108,41 +79,46 @@ class MiawClient extends events_1.EventEmitter {
108
79
  reconnectDelay: options.reconnectDelay || 3000,
109
80
  };
110
81
  // Initialize logger
111
- this.logger = this.options.logger || (0, pino_1.default)({
112
- level: this.options.debug ? 'debug' : 'silent'
113
- });
82
+ this.logger =
83
+ this.options.logger ||
84
+ pino({
85
+ level: this.options.debug ? "debug" : "silent",
86
+ });
114
87
  // Initialize handlers
115
- this.authHandler = new AuthHandler_1.AuthHandler(this.options.sessionPath, this.options.instanceId);
88
+ this.authHandler = new AuthHandler(this.options.sessionPath, this.options.instanceId);
116
89
  }
117
90
  /**
118
91
  * Connect to WhatsApp
119
92
  */
120
93
  async connect() {
121
94
  try {
122
- this.updateConnectionState('connecting');
95
+ this.updateConnectionState("connecting");
123
96
  // Load auth state
124
97
  const { state, saveCreds } = await this.authHandler.initialize();
125
98
  // Get latest Baileys version
126
- const { version } = await (0, baileys_1.fetchLatestBaileysVersion)();
99
+ const { version } = await fetchLatestBaileysVersion();
127
100
  // Create socket
128
- this.socket = (0, baileys_1.default)({
101
+ this.socket = makeWASocket({
129
102
  version,
130
103
  logger: this.logger,
131
104
  printQRInTerminal: false,
132
105
  auth: {
133
106
  creds: state.creds,
134
- keys: (0, baileys_1.makeCacheableSignalKeyStore)(state.keys, this.logger),
107
+ keys: makeCacheableSignalKeyStore(state.keys, this.logger),
135
108
  },
136
- browser: ['Miaw', 'Chrome', '1.0.0'],
109
+ browser: ["Miaw", "Chrome", "1.0.0"],
137
110
  generateHighQualityLinkPreview: true,
111
+ // Enable app state sync for labels and other features
112
+ syncFullHistory: false,
113
+ fireInitQueries: true,
138
114
  });
139
115
  // Register event handlers
140
116
  this.registerSocketEvents(saveCreds);
141
- this.logger.info('Connection initiated');
117
+ this.logger.info("Connection initiated");
142
118
  }
143
119
  catch (error) {
144
- this.logger.error('Failed to connect:', error);
145
- this.emit('error', error);
120
+ this.logger.error("Failed to connect:", error);
121
+ this.emit("error", error);
146
122
  if (this.options.autoReconnect) {
147
123
  this.scheduleReconnect();
148
124
  }
@@ -155,56 +131,65 @@ class MiawClient extends events_1.EventEmitter {
155
131
  if (!this.socket)
156
132
  return;
157
133
  // Connection updates
158
- this.socket.ev.on('connection.update', async (update) => {
134
+ this.socket.ev.on("connection.update", async (update) => {
159
135
  const { connection, lastDisconnect, qr } = update;
160
136
  // Handle QR code
161
137
  if (qr) {
162
- this.updateConnectionState('qr_required');
163
- this.emit('qr', qr);
138
+ this.updateConnectionState("qr_required");
139
+ this.emit("qr", qr);
164
140
  }
165
141
  // Handle connection state
166
- if (connection === 'close') {
142
+ if (connection === "close") {
167
143
  const shouldReconnect = this.handleDisconnect(lastDisconnect);
168
144
  if (shouldReconnect && this.options.autoReconnect) {
169
145
  this.scheduleReconnect();
170
146
  }
171
147
  }
172
- else if (connection === 'open') {
148
+ else if (connection === "open") {
173
149
  this.reconnectAttempts = 0;
174
- this.updateConnectionState('connected');
175
- this.emit('ready');
176
- this.logger.info('Connected to WhatsApp');
150
+ this.updateConnectionState("connected");
151
+ this.emit("ready");
152
+ this.logger.info("Connected to WhatsApp");
153
+ // Sync app state to populate labels (WhatsApp Business)
154
+ // Labels are stored in the 'regular' app state collection
155
+ this.syncLabelsFromAppState().catch((error) => {
156
+ this.logger.warn("Failed to sync labels from app state:", error);
157
+ });
177
158
  }
178
159
  });
179
160
  // Credentials update
180
- this.socket.ev.on('creds.update', async () => {
161
+ this.socket.ev.on("creds.update", async () => {
181
162
  await saveCreds();
182
- this.emit('session_saved');
163
+ this.emit("session_saved");
183
164
  });
184
- // Contact updates - build LID to JID mapping
185
- this.socket.ev.on('contacts.upsert', (contacts) => {
165
+ // Contact updates - build LID to JID mapping and populate contacts store
166
+ this.socket.ev.on("contacts.upsert", (contacts) => {
186
167
  this.updateLidToJidMapping(contacts);
168
+ this.updateContactsStore(contacts);
187
169
  });
188
- this.socket.ev.on('contacts.update', (contacts) => {
170
+ this.socket.ev.on("contacts.update", (contacts) => {
189
171
  this.updateLidToJidMapping(contacts);
172
+ this.updateContactsStore(contacts);
190
173
  });
191
- // Chat updates - extract LID mappings from chat data
192
- this.socket.ev.on('chats.upsert', (chats) => {
174
+ // Chat updates - extract LID mappings from chat data and populate chats store
175
+ this.socket.ev.on("chats.upsert", (chats) => {
193
176
  this.updateLidFromChats(chats);
177
+ this.updateChatsStore(chats);
194
178
  });
195
- this.socket.ev.on('chats.update', (chats) => {
179
+ this.socket.ev.on("chats.update", (chats) => {
196
180
  this.updateLidFromChats(chats);
181
+ this.updateChatsStore(chats);
197
182
  });
198
183
  // Messages
199
- this.socket.ev.on('messages.upsert', async (m) => {
200
- if (m.type !== 'notify')
184
+ this.socket.ev.on("messages.upsert", async (m) => {
185
+ if (m.type !== "notify")
201
186
  return;
202
187
  for (const msg of m.messages) {
203
188
  // Debug: Log raw Baileys message structure
204
189
  if (this.options.debug) {
205
- console.log('\n========== RAW BAILEYS MESSAGE ==========');
190
+ console.log("\n========== RAW BAILEYS MESSAGE ==========");
206
191
  console.log(JSON.stringify(msg, null, 2));
207
- console.log('=========================================\n');
192
+ console.log("=========================================\n");
208
193
  }
209
194
  // Check for protocol messages (edits and deletes)
210
195
  const protocolMessage = msg.message?.protocolMessage;
@@ -214,42 +199,50 @@ class MiawClient extends events_1.EventEmitter {
214
199
  }
215
200
  // Build LID to JID mapping from incoming messages
216
201
  // Incoming messages have remoteJid (phone) and senderLid (LID)
217
- if (!msg.key.fromMe && msg.key.senderLid && msg.key.remoteJid) {
218
- const lid = msg.key.senderLid.endsWith('@lid')
219
- ? msg.key.senderLid
220
- : `${msg.key.senderLid}@lid`;
221
- this.lidToJidMap.set(lid, msg.key.remoteJid);
202
+ // Note: senderLid may exist at runtime but isn't in Baileys v7 types
203
+ const msgKey = msg.key;
204
+ if (!msgKey.fromMe && msgKey.senderLid && msgKey.remoteJid) {
205
+ const lid = msgKey.senderLid.endsWith("@lid")
206
+ ? msgKey.senderLid
207
+ : `${msgKey.senderLid}@lid`;
208
+ this.lidToJidMap.set(lid, msgKey.remoteJid);
222
209
  if (this.options.debug) {
223
210
  console.log(`[LID Mapping] ${lid} -> ${msg.key.remoteJid}`);
224
211
  }
225
212
  }
226
- const normalized = MessageHandler_1.MessageHandler.normalize({ messages: [msg] });
213
+ const normalized = MessageHandler.normalize({ messages: [msg] });
227
214
  if (normalized) {
228
- this.emit('message', normalized);
215
+ // Store message in messagesStore (v0.9.0)
216
+ const chatJid = normalized.from;
217
+ if (!this.messagesStore.has(chatJid)) {
218
+ this.messagesStore.set(chatJid, []);
219
+ }
220
+ this.messagesStore.get(chatJid).push(normalized);
221
+ this.emit("message", normalized);
229
222
  }
230
223
  }
231
224
  });
232
225
  // Reactions
233
- this.socket.ev.on('messages.reaction', (reactions) => {
226
+ this.socket.ev.on("messages.reaction", (reactions) => {
234
227
  for (const { key, reaction } of reactions) {
235
228
  const reactionData = {
236
- messageId: key.id || '',
237
- chatId: key.remoteJid || '',
238
- reactorId: reaction.key?.participant || reaction.key?.remoteJid || '',
239
- emoji: reaction.text || '',
229
+ messageId: key.id || "",
230
+ chatId: key.remoteJid || "",
231
+ reactorId: reaction.key?.participant || reaction.key?.remoteJid || "",
232
+ emoji: reaction.text || "",
240
233
  isRemoval: !reaction.text,
241
234
  raw: { key, reaction },
242
235
  };
243
236
  if (this.options.debug) {
244
- console.log('\n========== REACTION ==========');
237
+ console.log("\n========== REACTION ==========");
245
238
  console.log(JSON.stringify(reactionData, null, 2));
246
- console.log('==============================\n');
239
+ console.log("==============================\n");
247
240
  }
248
- this.emit('message_reaction', reactionData);
241
+ this.emit("message_reaction", reactionData);
249
242
  }
250
243
  });
251
244
  // Presence updates
252
- this.socket.ev.on('presence.update', (presence) => {
245
+ this.socket.ev.on("presence.update", (presence) => {
253
246
  const jid = presence.id;
254
247
  const presences = presence.presences;
255
248
  for (const [participantJid, presenceData] of Object.entries(presences)) {
@@ -259,11 +252,35 @@ class MiawClient extends events_1.EventEmitter {
259
252
  lastSeen: presenceData.lastSeen,
260
253
  };
261
254
  if (this.options.debug) {
262
- console.log('\n========== PRESENCE UPDATE ==========');
255
+ console.log("\n========== PRESENCE UPDATE ==========");
263
256
  console.log(JSON.stringify(update, null, 2));
264
- console.log('=====================================\n');
257
+ console.log("=====================================\n");
258
+ }
259
+ this.emit("presence", update);
260
+ }
261
+ });
262
+ // Label updates (WhatsApp Business)
263
+ this.socket.ev.on("labels.edit", (label) => {
264
+ if (this.options.debug) {
265
+ console.log("\n========== LABEL UPDATE ==========");
266
+ console.log(JSON.stringify(label, null, 2));
267
+ console.log("==================================\n");
268
+ }
269
+ // Update label in store
270
+ if (label.id) {
271
+ if (label.deleted) {
272
+ this.labelsStore.delete(label.id);
273
+ }
274
+ else {
275
+ const labelData = {
276
+ id: label.id,
277
+ name: label.name || "",
278
+ color: label.color ?? 0,
279
+ predefinedId: label.predefinedId,
280
+ deleted: label.deleted,
281
+ };
282
+ this.labelsStore.set(label.id, labelData);
265
283
  }
266
- this.emit('presence', update);
267
284
  }
268
285
  });
269
286
  }
@@ -276,18 +293,18 @@ class MiawClient extends events_1.EventEmitter {
276
293
  // Type 0 = REVOKE (delete)
277
294
  if (type === 0 && key) {
278
295
  const deletion = {
279
- messageId: key.id || '',
280
- chatId: key.remoteJid || msg.key.remoteJid || '',
296
+ messageId: key.id || "",
297
+ chatId: key.remoteJid || msg.key.remoteJid || "",
281
298
  fromMe: key.fromMe || false,
282
299
  participant: key.participant,
283
300
  raw: msg,
284
301
  };
285
302
  if (this.options.debug) {
286
- console.log('\n========== MESSAGE DELETED ==========');
303
+ console.log("\n========== MESSAGE DELETED ==========");
287
304
  console.log(JSON.stringify(deletion, null, 2));
288
- console.log('=====================================\n');
305
+ console.log("=====================================\n");
289
306
  }
290
- this.emit('message_delete', deletion);
307
+ this.emit("message_delete", deletion);
291
308
  }
292
309
  // Type 14 = MESSAGE_EDIT
293
310
  if (type === 14 && protocolMessage.editedMessage) {
@@ -297,8 +314,8 @@ class MiawClient extends events_1.EventEmitter {
297
314
  editedMessage.imageMessage?.caption ||
298
315
  editedMessage.videoMessage?.caption;
299
316
  const edit = {
300
- messageId: key?.id || '',
301
- chatId: key?.remoteJid || msg.key.remoteJid || '',
317
+ messageId: key?.id || "",
318
+ chatId: key?.remoteJid || msg.key.remoteJid || "",
302
319
  newText,
303
320
  editTimestamp: protocolMessage.timestampMs
304
321
  ? Number(protocolMessage.timestampMs)
@@ -306,11 +323,11 @@ class MiawClient extends events_1.EventEmitter {
306
323
  raw: msg,
307
324
  };
308
325
  if (this.options.debug) {
309
- console.log('\n========== MESSAGE EDITED ==========');
326
+ console.log("\n========== MESSAGE EDITED ==========");
310
327
  console.log(JSON.stringify(edit, null, 2));
311
- console.log('====================================\n');
328
+ console.log("====================================\n");
312
329
  }
313
- this.emit('message_edit', edit);
330
+ this.emit("message_edit", edit);
314
331
  }
315
332
  }
316
333
  /**
@@ -319,14 +336,14 @@ class MiawClient extends events_1.EventEmitter {
319
336
  updateLidToJidMapping(contacts) {
320
337
  for (const contact of contacts) {
321
338
  // Contact has both lid and jid - create mapping
322
- if (contact.lid && contact.id && !contact.id.endsWith('@lid')) {
339
+ if (contact.lid && contact.id && !contact.id.endsWith("@lid")) {
323
340
  this.lidToJidMap.set(contact.lid, contact.id);
324
341
  if (this.options.debug) {
325
342
  console.log(`[Contact LID Mapping] ${contact.lid} -> ${contact.id}`);
326
343
  }
327
344
  }
328
345
  // Also check if id is the LID and jid field exists
329
- if (contact.id?.endsWith('@lid') && contact.jid) {
346
+ if (contact.id?.endsWith("@lid") && contact.jid) {
330
347
  this.lidToJidMap.set(contact.id, contact.jid);
331
348
  if (this.options.debug) {
332
349
  console.log(`[Contact LID Mapping] ${contact.id} -> ${contact.jid}`);
@@ -334,14 +351,68 @@ class MiawClient extends events_1.EventEmitter {
334
351
  }
335
352
  }
336
353
  }
354
+ /**
355
+ * Update in-memory contacts store (v0.9.0)
356
+ * @param contacts - Array of contact objects from Baileys
357
+ */
358
+ updateContactsStore(contacts) {
359
+ for (const contact of contacts) {
360
+ // Extract the JID (prefer non-lid IDs)
361
+ const jid = contact.id?.endsWith("@lid")
362
+ ? contact.jid || contact.id
363
+ : contact.id;
364
+ if (!jid)
365
+ continue;
366
+ // Extract phone number from JID
367
+ const phone = jid.endsWith("@s.whatsapp.net")
368
+ ? jid.replace("@s.whatsapp.net", "")
369
+ : undefined;
370
+ // Build contact info
371
+ const contactInfo = {
372
+ jid,
373
+ phone,
374
+ name: contact.name || contact.notify || undefined,
375
+ };
376
+ // Update store
377
+ this.contactsStore.set(jid, contactInfo);
378
+ }
379
+ }
380
+ /**
381
+ * Update in-memory chats store (v0.9.0)
382
+ * @param chats - Array of chat objects from Baileys
383
+ */
384
+ updateChatsStore(chats) {
385
+ for (const chat of chats) {
386
+ const jid = chat.id;
387
+ if (!jid)
388
+ continue;
389
+ // Extract phone number from JID
390
+ const phone = jid.endsWith("@s.whatsapp.net")
391
+ ? jid.replace("@s.whatsapp.net", "")
392
+ : undefined;
393
+ // Build chat info
394
+ const chatInfo = {
395
+ jid,
396
+ phone,
397
+ name: chat.name || undefined,
398
+ isGroup: jid.endsWith("@g.us"),
399
+ lastMessageTimestamp: chat.timestamp || undefined,
400
+ unreadCount: chat.unreadCount || undefined,
401
+ isArchived: chat.archived || false,
402
+ isPinned: chat.pinned || false,
403
+ };
404
+ // Update store
405
+ this.chatsStore.set(jid, chatInfo);
406
+ }
407
+ }
337
408
  /**
338
409
  * Update LID to JID mapping from chat data
339
410
  */
340
411
  updateLidFromChats(chats) {
341
412
  for (const chat of chats) {
342
413
  // Chat may have both id (could be phone or LID) and lidJid
343
- if (chat.lidJid && chat.id && !chat.id.endsWith('@lid')) {
344
- const lid = chat.lidJid.endsWith('@lid')
414
+ if (chat.lidJid && chat.id && !chat.id.endsWith("@lid")) {
415
+ const lid = chat.lidJid.endsWith("@lid")
345
416
  ? chat.lidJid
346
417
  : `${chat.lidJid}@lid`;
347
418
  this.lidToJidMap.set(lid, chat.id);
@@ -350,7 +421,7 @@ class MiawClient extends events_1.EventEmitter {
350
421
  }
351
422
  }
352
423
  // Reverse: if id is LID and we have a phone JID
353
- if (chat.id?.endsWith('@lid') && chat.jid) {
424
+ if (chat.id?.endsWith("@lid") && chat.jid) {
354
425
  this.lidToJidMap.set(chat.id, chat.jid);
355
426
  if (this.options.debug) {
356
427
  console.log(`[Chat LID Mapping] ${chat.id} -> ${chat.jid}`);
@@ -364,7 +435,7 @@ class MiawClient extends events_1.EventEmitter {
364
435
  * @returns The phone number JID if found, or the original LID
365
436
  */
366
437
  resolveLidToJid(lid) {
367
- if (!lid?.endsWith('@lid')) {
438
+ if (!lid?.endsWith("@lid")) {
368
439
  return lid;
369
440
  }
370
441
  return this.lidToJidMap.get(lid) || lid;
@@ -376,8 +447,8 @@ class MiawClient extends events_1.EventEmitter {
376
447
  */
377
448
  getPhoneFromJid(jid) {
378
449
  const resolved = this.resolveLidToJid(jid);
379
- if (resolved.endsWith('@s.whatsapp.net')) {
380
- return resolved.replace('@s.whatsapp.net', '');
450
+ if (resolved.endsWith("@s.whatsapp.net")) {
451
+ return resolved.replace("@s.whatsapp.net", "");
381
452
  }
382
453
  return undefined;
383
454
  }
@@ -388,8 +459,8 @@ class MiawClient extends events_1.EventEmitter {
388
459
  * @param phoneJid - The phone JID (e.g., '6281234567890@s.whatsapp.net' or just '6281234567890')
389
460
  */
390
461
  registerLidMapping(lid, phoneJid) {
391
- const normalizedLid = lid.includes('@') ? lid : `${lid}@lid`;
392
- const normalizedJid = phoneJid.includes('@')
462
+ const normalizedLid = lid.includes("@") ? lid : `${lid}@lid`;
463
+ const normalizedJid = phoneJid.includes("@")
393
464
  ? phoneJid
394
465
  : `${phoneJid}@s.whatsapp.net`;
395
466
  this.lidToJidMap.set(normalizedLid, normalizedJid);
@@ -418,6 +489,15 @@ class MiawClient extends events_1.EventEmitter {
418
489
  clearLidCache() {
419
490
  this.lidToJidMap.clear();
420
491
  }
492
+ /**
493
+ * Clear session data for this instance.
494
+ * This will delete all stored authentication credentials.
495
+ * After calling this, the next connect() will require scanning a new QR code.
496
+ * @returns true if session was cleared, false if no session existed
497
+ */
498
+ clearSession() {
499
+ return this.authHandler.clearSession();
500
+ }
421
501
  /**
422
502
  * Dispose client and clean up resources
423
503
  */
@@ -436,7 +516,7 @@ class MiawClient extends events_1.EventEmitter {
436
516
  this.socket.end(undefined);
437
517
  this.socket = null;
438
518
  }
439
- this.updateConnectionState('disconnected');
519
+ this.updateConnectionState("disconnected");
440
520
  }
441
521
  /**
442
522
  * Handle disconnection
@@ -444,13 +524,14 @@ class MiawClient extends events_1.EventEmitter {
444
524
  */
445
525
  handleDisconnect(lastDisconnect) {
446
526
  const statusCode = lastDisconnect?.error?.output?.statusCode;
447
- const reason = baileys_1.DisconnectReason[statusCode] || 'unknown';
448
- this.logger.info('Disconnected:', reason, 'Code:', statusCode);
449
- this.updateConnectionState('disconnected');
450
- this.emit('disconnected', reason);
451
- // Don't reconnect if logged out
452
- if (statusCode === baileys_1.DisconnectReason.loggedOut) {
453
- this.logger.info('Logged out, not reconnecting');
527
+ const reason = DisconnectReason[statusCode] || "unknown";
528
+ this.logger.info("Disconnected:", reason, "Code:", statusCode);
529
+ this.updateConnectionState("disconnected");
530
+ this.emit("disconnected", reason);
531
+ // Don't reconnect if logged out - clear session for fresh QR code on next connect
532
+ if (statusCode === DisconnectReason.loggedOut) {
533
+ this.logger.info("Logged out, clearing session for fresh authentication");
534
+ this.authHandler.clearSession();
454
535
  return false;
455
536
  }
456
537
  return true;
@@ -460,16 +541,16 @@ class MiawClient extends events_1.EventEmitter {
460
541
  */
461
542
  scheduleReconnect() {
462
543
  if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
463
- this.logger.error('Max reconnection attempts reached');
464
- this.emit('error', new Error('Max reconnection attempts reached'));
544
+ this.logger.error("Max reconnection attempts reached");
545
+ this.emit("error", new Error("Max reconnection attempts reached"));
465
546
  return;
466
547
  }
467
548
  if (this.reconnectTimer) {
468
549
  clearTimeout(this.reconnectTimer);
469
550
  }
470
551
  this.reconnectAttempts++;
471
- this.updateConnectionState('reconnecting');
472
- this.emit('reconnecting', this.reconnectAttempts);
552
+ this.updateConnectionState("reconnecting");
553
+ this.emit("reconnecting", this.reconnectAttempts);
473
554
  this.reconnectTimer = setTimeout(() => {
474
555
  this.logger.info(`Reconnecting... Attempt ${this.reconnectAttempts}`);
475
556
  this.connect();
@@ -480,7 +561,7 @@ class MiawClient extends events_1.EventEmitter {
480
561
  */
481
562
  updateConnectionState(state) {
482
563
  this.connectionState = state;
483
- this.emit('connection', state);
564
+ this.emit("connection", state);
484
565
  }
485
566
  /**
486
567
  * Send a text message
@@ -491,14 +572,16 @@ class MiawClient extends events_1.EventEmitter {
491
572
  async sendText(to, text, options) {
492
573
  try {
493
574
  if (!this.socket) {
494
- throw new Error('Not connected. Call connect() first.');
575
+ throw new Error("Not connected. Call connect() first.");
495
576
  }
496
- if (this.connectionState !== 'connected') {
577
+ if (this.connectionState !== "connected") {
497
578
  throw new Error(`Cannot send message. Connection state: ${this.connectionState}`);
498
579
  }
499
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
580
+ const jid = MessageHandler.formatPhoneToJid(to);
500
581
  // Build send options (for quoting/replying)
501
- const sendOptions = options?.quoted?.raw ? { quoted: options.quoted.raw } : undefined;
582
+ const sendOptions = options?.quoted?.raw
583
+ ? { quoted: options.quoted.raw }
584
+ : undefined;
502
585
  const result = await this.socket.sendMessage(jid, { text }, sendOptions);
503
586
  return {
504
587
  success: true,
@@ -506,7 +589,7 @@ class MiawClient extends events_1.EventEmitter {
506
589
  };
507
590
  }
508
591
  catch (error) {
509
- this.logger.error('Failed to send message:', error);
592
+ this.logger.error("Failed to send message:", error);
510
593
  return {
511
594
  success: false,
512
595
  error: error.message,
@@ -522,12 +605,12 @@ class MiawClient extends events_1.EventEmitter {
522
605
  async sendImage(to, image, options) {
523
606
  try {
524
607
  if (!this.socket) {
525
- throw new Error('Not connected. Call connect() first.');
608
+ throw new Error("Not connected. Call connect() first.");
526
609
  }
527
- if (this.connectionState !== 'connected') {
610
+ if (this.connectionState !== "connected") {
528
611
  throw new Error(`Cannot send message. Connection state: ${this.connectionState}`);
529
612
  }
530
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
613
+ const jid = MessageHandler.formatPhoneToJid(to);
531
614
  // Build image message payload
532
615
  const imageContent = {
533
616
  image: Buffer.isBuffer(image) ? image : { url: image },
@@ -535,7 +618,9 @@ class MiawClient extends events_1.EventEmitter {
535
618
  viewOnce: options?.viewOnce,
536
619
  };
537
620
  // Build send options (for quoting/replying)
538
- const sendOptions = options?.quoted?.raw ? { quoted: options.quoted.raw } : undefined;
621
+ const sendOptions = options?.quoted?.raw
622
+ ? { quoted: options.quoted.raw }
623
+ : undefined;
539
624
  const result = await this.socket.sendMessage(jid, imageContent, sendOptions);
540
625
  return {
541
626
  success: true,
@@ -543,7 +628,7 @@ class MiawClient extends events_1.EventEmitter {
543
628
  };
544
629
  }
545
630
  catch (error) {
546
- this.logger.error('Failed to send image:', error);
631
+ this.logger.error("Failed to send image:", error);
547
632
  return {
548
633
  success: false,
549
634
  error: error.message,
@@ -559,12 +644,12 @@ class MiawClient extends events_1.EventEmitter {
559
644
  async sendDocument(to, document, options) {
560
645
  try {
561
646
  if (!this.socket) {
562
- throw new Error('Not connected. Call connect() first.');
647
+ throw new Error("Not connected. Call connect() first.");
563
648
  }
564
- if (this.connectionState !== 'connected') {
649
+ if (this.connectionState !== "connected") {
565
650
  throw new Error(`Cannot send message. Connection state: ${this.connectionState}`);
566
651
  }
567
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
652
+ const jid = MessageHandler.formatPhoneToJid(to);
568
653
  // Determine filename and mimetype
569
654
  let fileName = options?.fileName;
570
655
  let mimetype = options?.mimetype;
@@ -579,12 +664,14 @@ class MiawClient extends events_1.EventEmitter {
579
664
  // Build document message payload
580
665
  const documentContent = {
581
666
  document: Buffer.isBuffer(document) ? document : { url: document },
582
- fileName: fileName || 'document',
583
- mimetype: mimetype || 'application/octet-stream',
667
+ fileName: fileName || "document",
668
+ mimetype: mimetype || "application/octet-stream",
584
669
  caption: options?.caption,
585
670
  };
586
671
  // Build send options (for quoting/replying)
587
- const sendOptions = options?.quoted?.raw ? { quoted: options.quoted.raw } : undefined;
672
+ const sendOptions = options?.quoted?.raw
673
+ ? { quoted: options.quoted.raw }
674
+ : undefined;
588
675
  const result = await this.socket.sendMessage(jid, documentContent, sendOptions);
589
676
  return {
590
677
  success: true,
@@ -592,7 +679,7 @@ class MiawClient extends events_1.EventEmitter {
592
679
  };
593
680
  }
594
681
  catch (error) {
595
- this.logger.error('Failed to send document:', error);
682
+ this.logger.error("Failed to send document:", error);
596
683
  return {
597
684
  success: false,
598
685
  error: error.message,
@@ -608,12 +695,12 @@ class MiawClient extends events_1.EventEmitter {
608
695
  async sendVideo(to, video, options) {
609
696
  try {
610
697
  if (!this.socket) {
611
- throw new Error('Not connected. Call connect() first.');
698
+ throw new Error("Not connected. Call connect() first.");
612
699
  }
613
- if (this.connectionState !== 'connected') {
700
+ if (this.connectionState !== "connected") {
614
701
  throw new Error(`Cannot send message. Connection state: ${this.connectionState}`);
615
702
  }
616
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
703
+ const jid = MessageHandler.formatPhoneToJid(to);
617
704
  // Build video message payload
618
705
  const videoContent = {
619
706
  video: Buffer.isBuffer(video) ? video : { url: video },
@@ -623,7 +710,9 @@ class MiawClient extends events_1.EventEmitter {
623
710
  ptv: options?.ptv,
624
711
  };
625
712
  // Build send options (for quoting/replying)
626
- const sendOptions = options?.quoted?.raw ? { quoted: options.quoted.raw } : undefined;
713
+ const sendOptions = options?.quoted?.raw
714
+ ? { quoted: options.quoted.raw }
715
+ : undefined;
627
716
  const result = await this.socket.sendMessage(jid, videoContent, sendOptions);
628
717
  return {
629
718
  success: true,
@@ -631,7 +720,7 @@ class MiawClient extends events_1.EventEmitter {
631
720
  };
632
721
  }
633
722
  catch (error) {
634
- this.logger.error('Failed to send video:', error);
723
+ this.logger.error("Failed to send video:", error);
635
724
  return {
636
725
  success: false,
637
726
  error: error.message,
@@ -647,12 +736,12 @@ class MiawClient extends events_1.EventEmitter {
647
736
  async sendAudio(to, audio, options) {
648
737
  try {
649
738
  if (!this.socket) {
650
- throw new Error('Not connected. Call connect() first.');
739
+ throw new Error("Not connected. Call connect() first.");
651
740
  }
652
- if (this.connectionState !== 'connected') {
741
+ if (this.connectionState !== "connected") {
653
742
  throw new Error(`Cannot send message. Connection state: ${this.connectionState}`);
654
743
  }
655
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
744
+ const jid = MessageHandler.formatPhoneToJid(to);
656
745
  // Determine mimetype
657
746
  let mimetype = options?.mimetype;
658
747
  if (!mimetype && !Buffer.isBuffer(audio)) {
@@ -661,11 +750,13 @@ class MiawClient extends events_1.EventEmitter {
661
750
  // Build audio message payload
662
751
  const audioContent = {
663
752
  audio: Buffer.isBuffer(audio) ? audio : { url: audio },
664
- mimetype: mimetype || 'audio/mp4',
753
+ mimetype: mimetype || "audio/mp4",
665
754
  ptt: options?.ptt,
666
755
  };
667
756
  // Build send options (for quoting/replying)
668
- const sendOptions = options?.quoted?.raw ? { quoted: options.quoted.raw } : undefined;
757
+ const sendOptions = options?.quoted?.raw
758
+ ? { quoted: options.quoted.raw }
759
+ : undefined;
669
760
  const result = await this.socket.sendMessage(jid, audioContent, sendOptions);
670
761
  return {
671
762
  success: true,
@@ -673,7 +764,7 @@ class MiawClient extends events_1.EventEmitter {
673
764
  };
674
765
  }
675
766
  catch (error) {
676
- this.logger.error('Failed to send audio:', error);
767
+ this.logger.error("Failed to send audio:", error);
677
768
  return {
678
769
  success: false,
679
770
  error: error.message,
@@ -688,14 +779,14 @@ class MiawClient extends events_1.EventEmitter {
688
779
  async downloadMedia(message) {
689
780
  try {
690
781
  if (!message.raw) {
691
- throw new Error('Message does not contain raw Baileys data. Cannot download media.');
782
+ throw new Error("Message does not contain raw Baileys data. Cannot download media.");
692
783
  }
693
784
  // Check if this is a media message
694
- const mediaTypes = ['image', 'video', 'audio', 'document', 'sticker'];
785
+ const mediaTypes = ["image", "video", "audio", "document", "sticker"];
695
786
  if (!mediaTypes.includes(message.type)) {
696
787
  throw new Error(`Message type '${message.type}' is not a downloadable media type.`);
697
788
  }
698
- const buffer = await (0, baileys_1.downloadMediaMessage)(message.raw, 'buffer', {}, {
789
+ const buffer = await downloadMediaMessage(message.raw, "buffer", {}, {
699
790
  logger: this.logger,
700
791
  // reuploadRequest allows re-uploading expired media
701
792
  reuploadRequest: this.socket
@@ -705,7 +796,7 @@ class MiawClient extends events_1.EventEmitter {
705
796
  return buffer;
706
797
  }
707
798
  catch (error) {
708
- this.logger.error('Failed to download media:', error);
799
+ this.logger.error("Failed to download media:", error);
709
800
  return null;
710
801
  }
711
802
  }
@@ -720,13 +811,13 @@ class MiawClient extends events_1.EventEmitter {
720
811
  async checkNumber(phone) {
721
812
  try {
722
813
  if (!this.socket) {
723
- throw new Error('Not connected. Call connect() first.');
814
+ throw new Error("Not connected. Call connect() first.");
724
815
  }
725
- if (this.connectionState !== 'connected') {
816
+ if (this.connectionState !== "connected") {
726
817
  throw new Error(`Cannot check number. Connection state: ${this.connectionState}`);
727
818
  }
728
819
  // Clean phone number - remove non-digits
729
- const cleanPhone = phone.replace(/\D/g, '');
820
+ const cleanPhone = phone.replace(/\D/g, "");
730
821
  const results = await this.socket.onWhatsApp(cleanPhone);
731
822
  const result = results?.[0];
732
823
  return {
@@ -735,7 +826,7 @@ class MiawClient extends events_1.EventEmitter {
735
826
  };
736
827
  }
737
828
  catch (error) {
738
- this.logger.error('Failed to check number:', error);
829
+ this.logger.error("Failed to check number:", error);
739
830
  return {
740
831
  exists: false,
741
832
  error: error.message,
@@ -750,13 +841,13 @@ class MiawClient extends events_1.EventEmitter {
750
841
  async checkNumbers(phones) {
751
842
  try {
752
843
  if (!this.socket) {
753
- throw new Error('Not connected. Call connect() first.');
844
+ throw new Error("Not connected. Call connect() first.");
754
845
  }
755
- if (this.connectionState !== 'connected') {
846
+ if (this.connectionState !== "connected") {
756
847
  throw new Error(`Cannot check numbers. Connection state: ${this.connectionState}`);
757
848
  }
758
849
  // Clean all phone numbers
759
- const cleanPhones = phones.map((p) => p.replace(/\D/g, ''));
850
+ const cleanPhones = phones.map((p) => p.replace(/\D/g, ""));
760
851
  const results = await this.socket.onWhatsApp(...cleanPhones);
761
852
  return (results || []).map((result) => ({
762
853
  exists: !!result?.exists,
@@ -764,7 +855,7 @@ class MiawClient extends events_1.EventEmitter {
764
855
  }));
765
856
  }
766
857
  catch (error) {
767
- this.logger.error('Failed to check numbers:', error);
858
+ this.logger.error("Failed to check numbers:", error);
768
859
  return phones.map(() => ({
769
860
  exists: false,
770
861
  error: error.message,
@@ -779,18 +870,20 @@ class MiawClient extends events_1.EventEmitter {
779
870
  async getContactInfo(jidOrPhone) {
780
871
  try {
781
872
  if (!this.socket) {
782
- throw new Error('Not connected. Call connect() first.');
873
+ throw new Error("Not connected. Call connect() first.");
783
874
  }
784
- if (this.connectionState !== 'connected') {
875
+ if (this.connectionState !== "connected") {
785
876
  throw new Error(`Cannot get contact info. Connection state: ${this.connectionState}`);
786
877
  }
787
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(jidOrPhone);
878
+ const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
788
879
  // Fetch status
789
880
  let status;
790
881
  try {
791
882
  const statusResult = await this.socket.fetchStatus(jid);
792
883
  // fetchStatus returns an array, get first result
793
- const firstResult = Array.isArray(statusResult) ? statusResult[0] : statusResult;
884
+ const firstResult = Array.isArray(statusResult)
885
+ ? statusResult[0]
886
+ : statusResult;
794
887
  status = firstResult?.status?.status || undefined;
795
888
  }
796
889
  catch {
@@ -806,8 +899,8 @@ class MiawClient extends events_1.EventEmitter {
806
899
  // Not a business account or not available
807
900
  }
808
901
  // Extract phone from JID
809
- const phone = jid.endsWith('@s.whatsapp.net')
810
- ? jid.replace('@s.whatsapp.net', '')
902
+ const phone = jid.endsWith("@s.whatsapp.net")
903
+ ? jid.replace("@s.whatsapp.net", "")
811
904
  : undefined;
812
905
  return {
813
906
  jid,
@@ -817,7 +910,7 @@ class MiawClient extends events_1.EventEmitter {
817
910
  };
818
911
  }
819
912
  catch (error) {
820
- this.logger.error('Failed to get contact info:', error);
913
+ this.logger.error("Failed to get contact info:", error);
821
914
  return null;
822
915
  }
823
916
  }
@@ -829,12 +922,12 @@ class MiawClient extends events_1.EventEmitter {
829
922
  async getBusinessProfile(jidOrPhone) {
830
923
  try {
831
924
  if (!this.socket) {
832
- throw new Error('Not connected. Call connect() first.');
925
+ throw new Error("Not connected. Call connect() first.");
833
926
  }
834
- if (this.connectionState !== 'connected') {
927
+ if (this.connectionState !== "connected") {
835
928
  throw new Error(`Cannot get business profile. Connection state: ${this.connectionState}`);
836
929
  }
837
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(jidOrPhone);
930
+ const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
838
931
  const profile = await this.socket.getBusinessProfile(jid);
839
932
  if (!profile) {
840
933
  return null;
@@ -842,13 +935,15 @@ class MiawClient extends events_1.EventEmitter {
842
935
  return {
843
936
  description: profile.description || undefined,
844
937
  category: profile.category || undefined,
845
- website: Array.isArray(profile.website) ? profile.website[0] : profile.website,
938
+ website: Array.isArray(profile.website)
939
+ ? profile.website[0]
940
+ : profile.website,
846
941
  email: profile.email || undefined,
847
942
  address: profile.address || undefined,
848
943
  };
849
944
  }
850
945
  catch (error) {
851
- this.logger.error('Failed to get business profile:', error);
946
+ this.logger.error("Failed to get business profile:", error);
852
947
  return null;
853
948
  }
854
949
  }
@@ -861,21 +956,244 @@ class MiawClient extends events_1.EventEmitter {
861
956
  async getProfilePicture(jidOrPhone, highRes = false) {
862
957
  try {
863
958
  if (!this.socket) {
864
- throw new Error('Not connected. Call connect() first.');
959
+ throw new Error("Not connected. Call connect() first.");
865
960
  }
866
- if (this.connectionState !== 'connected') {
961
+ if (this.connectionState !== "connected") {
867
962
  throw new Error(`Cannot get profile picture. Connection state: ${this.connectionState}`);
868
963
  }
869
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(jidOrPhone);
870
- const url = await this.socket.profilePictureUrl(jid, highRes ? 'image' : 'preview');
964
+ const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
965
+ const url = await this.socket.profilePictureUrl(jid, highRes ? "image" : "preview");
871
966
  return url || null;
872
967
  }
873
968
  catch (error) {
874
969
  // Profile picture might not be available (privacy settings)
875
- this.logger.debug('Profile picture not available:', error);
970
+ this.logger.debug("Profile picture not available:", error);
971
+ return null;
972
+ }
973
+ }
974
+ // ============================================
975
+ // Basic GET Operations (v0.9.0)
976
+ // ============================================
977
+ /**
978
+ * Fetch all contacts from the in-memory store
979
+ * Note: Contacts are populated via history sync and contact events
980
+ * @returns FetchAllContactsResult with list of contacts
981
+ */
982
+ async fetchAllContacts() {
983
+ try {
984
+ const contacts = Array.from(this.contactsStore.values());
985
+ return {
986
+ success: true,
987
+ contacts,
988
+ };
989
+ }
990
+ catch (error) {
991
+ this.logger.error("Failed to fetch contacts:", error);
992
+ return {
993
+ success: false,
994
+ error: error.message,
995
+ };
996
+ }
997
+ }
998
+ /**
999
+ * Fetch all groups the user is participating in
1000
+ * @returns FetchAllGroupsResult with list of groups
1001
+ */
1002
+ async fetchAllGroups() {
1003
+ try {
1004
+ if (!this.socket) {
1005
+ throw new Error("Not connected. Call connect() first.");
1006
+ }
1007
+ if (this.connectionState !== "connected") {
1008
+ throw new Error(`Cannot fetch groups. Connection state: ${this.connectionState}`);
1009
+ }
1010
+ const groups = await this.socket.groupFetchAllParticipating();
1011
+ const groupList = Object.values(groups).map((g) => ({
1012
+ jid: g.id,
1013
+ name: g.subject,
1014
+ description: g.desc || undefined,
1015
+ owner: g.owner || undefined,
1016
+ createdAt: g.creation,
1017
+ participantCount: g.participants?.length || 0,
1018
+ participants: g.participants?.map((p) => ({
1019
+ jid: p.id,
1020
+ role: p.admin === "superadmin"
1021
+ ? "superadmin"
1022
+ : p.admin === "admin"
1023
+ ? "admin"
1024
+ : "member",
1025
+ })) || [],
1026
+ announce: g.announce,
1027
+ restrict: g.restrict,
1028
+ }));
1029
+ return {
1030
+ success: true,
1031
+ groups: groupList,
1032
+ };
1033
+ }
1034
+ catch (error) {
1035
+ this.logger.error("Failed to fetch groups:", error);
1036
+ return {
1037
+ success: false,
1038
+ error: error.message,
1039
+ };
1040
+ }
1041
+ }
1042
+ /**
1043
+ * Get own profile information
1044
+ * @returns OwnProfile or null if not available
1045
+ */
1046
+ async getOwnProfile() {
1047
+ try {
1048
+ if (!this.socket) {
1049
+ throw new Error("Not connected. Call connect() first.");
1050
+ }
1051
+ if (this.connectionState !== "connected") {
1052
+ throw new Error(`Cannot get own profile. Connection state: ${this.connectionState}`);
1053
+ }
1054
+ const jid = this.socket.user?.id;
1055
+ if (!jid) {
1056
+ throw new Error("User ID not available");
1057
+ }
1058
+ // Extract phone number from JID
1059
+ const phone = jid.endsWith("@s.whatsapp.net")
1060
+ ? jid.replace("@s.whatsapp.net", "")
1061
+ : undefined;
1062
+ // Fetch status
1063
+ let status;
1064
+ try {
1065
+ const statusResult = await this.socket.fetchStatus(jid);
1066
+ const firstResult = Array.isArray(statusResult)
1067
+ ? statusResult[0]
1068
+ : statusResult;
1069
+ status = firstResult?.status?.status || undefined;
1070
+ }
1071
+ catch {
1072
+ // Status might not be available
1073
+ }
1074
+ // Fetch profile picture URL
1075
+ let pictureUrl;
1076
+ try {
1077
+ pictureUrl = (await this.socket.profilePictureUrl(jid)) || undefined;
1078
+ }
1079
+ catch {
1080
+ // Profile picture might not be available
1081
+ }
1082
+ // Check if business account
1083
+ let isBusiness = false;
1084
+ try {
1085
+ const businessProfile = await this.socket.getBusinessProfile(jid);
1086
+ isBusiness = !!businessProfile;
1087
+ }
1088
+ catch {
1089
+ // Not a business account
1090
+ }
1091
+ return {
1092
+ jid,
1093
+ phone,
1094
+ status,
1095
+ pictureUrl,
1096
+ isBusiness,
1097
+ };
1098
+ }
1099
+ catch (error) {
1100
+ this.logger.error("Failed to get own profile:", error);
876
1101
  return null;
877
1102
  }
878
1103
  }
1104
+ /**
1105
+ * Sync labels from WhatsApp app state
1106
+ * This triggers a resync of the 'regular' collection which contains labels
1107
+ * Labels will be emitted via labels.edit events and stored in labelsStore
1108
+ */
1109
+ async syncLabelsFromAppState() {
1110
+ if (!this.socket) {
1111
+ return;
1112
+ }
1113
+ try {
1114
+ // resyncAppState is provided by Baileys to sync app state collections
1115
+ // The 'regular' collection contains labels
1116
+ // The second parameter (false) means this is not an initial sync
1117
+ await this.socket.resyncAppState(["regular"], false);
1118
+ this.logger.info("App state sync completed, labels should be populated via labels.edit events");
1119
+ }
1120
+ catch (error) {
1121
+ // This is non-fatal - labels may already be synced or unavailable
1122
+ this.logger.debug("App state sync error (non-fatal):", error);
1123
+ }
1124
+ }
1125
+ /**
1126
+ * Fetch all labels from the in-memory store
1127
+ * Note: Labels are populated via history sync and label events
1128
+ * @param forceSync - If true, force a resync from WhatsApp before returning labels
1129
+ * @returns FetchAllLabelsResult with list of labels
1130
+ */
1131
+ async fetchAllLabels(forceSync = false) {
1132
+ try {
1133
+ // Force resync if requested or if store is empty (first call)
1134
+ if (forceSync || this.labelsStore.size === 0) {
1135
+ await this.syncLabelsFromAppState();
1136
+ // Give a brief moment for labels.edit events to be processed
1137
+ await new Promise((resolve) => setTimeout(resolve, 500));
1138
+ }
1139
+ const labels = Array.from(this.labelsStore.values());
1140
+ return {
1141
+ success: true,
1142
+ labels,
1143
+ };
1144
+ }
1145
+ catch (error) {
1146
+ this.logger.error("Failed to fetch labels:", error);
1147
+ return {
1148
+ success: false,
1149
+ error: error.message,
1150
+ };
1151
+ }
1152
+ }
1153
+ /**
1154
+ * Get chat messages from the in-memory store
1155
+ * Note: Messages are populated via messages.upsert events
1156
+ * @param jidOrPhone - Chat JID or phone number
1157
+ * @returns FetchChatMessagesResult with list of messages
1158
+ */
1159
+ async getChatMessages(jidOrPhone) {
1160
+ try {
1161
+ const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
1162
+ const messages = this.messagesStore.get(jid) || [];
1163
+ return {
1164
+ success: true,
1165
+ messages,
1166
+ };
1167
+ }
1168
+ catch (error) {
1169
+ this.logger.error("Failed to get chat messages:", error);
1170
+ return {
1171
+ success: false,
1172
+ error: error.message,
1173
+ };
1174
+ }
1175
+ }
1176
+ /**
1177
+ * Fetch all chats from the in-memory store
1178
+ * Note: Chats are populated via history sync and chat events
1179
+ * @returns FetchAllChatsResult with list of chats
1180
+ */
1181
+ async fetchAllChats() {
1182
+ try {
1183
+ const chats = Array.from(this.chatsStore.values());
1184
+ return {
1185
+ success: true,
1186
+ chats,
1187
+ };
1188
+ }
1189
+ catch (error) {
1190
+ this.logger.error("Failed to fetch chats:", error);
1191
+ return {
1192
+ success: false,
1193
+ error: error.message,
1194
+ };
1195
+ }
1196
+ }
879
1197
  // ============================================
880
1198
  // Group Methods (v0.4.0)
881
1199
  // ============================================
@@ -887,19 +1205,23 @@ class MiawClient extends events_1.EventEmitter {
887
1205
  async getGroupInfo(groupJid) {
888
1206
  try {
889
1207
  if (!this.socket) {
890
- throw new Error('Not connected. Call connect() first.');
1208
+ throw new Error("Not connected. Call connect() first.");
891
1209
  }
892
- if (this.connectionState !== 'connected') {
1210
+ if (this.connectionState !== "connected") {
893
1211
  throw new Error(`Cannot get group info. Connection state: ${this.connectionState}`);
894
1212
  }
895
1213
  // Ensure it's a group JID
896
- if (!groupJid.endsWith('@g.us')) {
897
- throw new Error('Invalid group JID. Must end with @g.us');
1214
+ if (!groupJid.endsWith("@g.us")) {
1215
+ throw new Error("Invalid group JID. Must end with @g.us");
898
1216
  }
899
1217
  const metadata = await this.socket.groupMetadata(groupJid);
900
1218
  const participants = metadata.participants.map((p) => ({
901
1219
  jid: p.id,
902
- role: p.admin === 'superadmin' ? 'superadmin' : p.admin === 'admin' ? 'admin' : 'member',
1220
+ role: p.admin === "superadmin"
1221
+ ? "superadmin"
1222
+ : p.admin === "admin"
1223
+ ? "admin"
1224
+ : "member",
903
1225
  }));
904
1226
  return {
905
1227
  jid: metadata.id,
@@ -914,7 +1236,7 @@ class MiawClient extends events_1.EventEmitter {
914
1236
  };
915
1237
  }
916
1238
  catch (error) {
917
- this.logger.error('Failed to get group info:', error);
1239
+ this.logger.error("Failed to get group info:", error);
918
1240
  return null;
919
1241
  }
920
1242
  }
@@ -939,17 +1261,17 @@ class MiawClient extends events_1.EventEmitter {
939
1261
  async sendReaction(message, emoji) {
940
1262
  try {
941
1263
  if (!this.socket) {
942
- throw new Error('Not connected. Call connect() first.');
1264
+ throw new Error("Not connected. Call connect() first.");
943
1265
  }
944
- if (this.connectionState !== 'connected') {
1266
+ if (this.connectionState !== "connected") {
945
1267
  throw new Error(`Cannot send reaction. Connection state: ${this.connectionState}`);
946
1268
  }
947
1269
  if (!message.raw?.key) {
948
- throw new Error('Message does not contain raw Baileys key data. Cannot send reaction.');
1270
+ throw new Error("Message does not contain raw Baileys key data. Cannot send reaction.");
949
1271
  }
950
1272
  const jid = message.raw.key.remoteJid;
951
1273
  if (!jid) {
952
- throw new Error('Message does not have a valid chat JID.');
1274
+ throw new Error("Message does not have a valid chat JID.");
953
1275
  }
954
1276
  const result = await this.socket.sendMessage(jid, {
955
1277
  react: {
@@ -963,7 +1285,7 @@ class MiawClient extends events_1.EventEmitter {
963
1285
  };
964
1286
  }
965
1287
  catch (error) {
966
- this.logger.error('Failed to send reaction:', error);
1288
+ this.logger.error("Failed to send reaction:", error);
967
1289
  return {
968
1290
  success: false,
969
1291
  error: error.message,
@@ -976,7 +1298,7 @@ class MiawClient extends events_1.EventEmitter {
976
1298
  * @returns SendMessageResult
977
1299
  */
978
1300
  async removeReaction(message) {
979
- return this.sendReaction(message, '');
1301
+ return this.sendReaction(message, "");
980
1302
  }
981
1303
  /**
982
1304
  * Forward a message to another chat
@@ -987,15 +1309,15 @@ class MiawClient extends events_1.EventEmitter {
987
1309
  async forwardMessage(message, to) {
988
1310
  try {
989
1311
  if (!this.socket) {
990
- throw new Error('Not connected. Call connect() first.');
1312
+ throw new Error("Not connected. Call connect() first.");
991
1313
  }
992
- if (this.connectionState !== 'connected') {
1314
+ if (this.connectionState !== "connected") {
993
1315
  throw new Error(`Cannot forward message. Connection state: ${this.connectionState}`);
994
1316
  }
995
1317
  if (!message.raw) {
996
- throw new Error('Message does not contain raw Baileys data. Cannot forward.');
1318
+ throw new Error("Message does not contain raw Baileys data. Cannot forward.");
997
1319
  }
998
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
1320
+ const jid = MessageHandler.formatPhoneToJid(to);
999
1321
  const result = await this.socket.sendMessage(jid, {
1000
1322
  forward: message.raw,
1001
1323
  });
@@ -1005,7 +1327,7 @@ class MiawClient extends events_1.EventEmitter {
1005
1327
  };
1006
1328
  }
1007
1329
  catch (error) {
1008
- this.logger.error('Failed to forward message:', error);
1330
+ this.logger.error("Failed to forward message:", error);
1009
1331
  return {
1010
1332
  success: false,
1011
1333
  error: error.message,
@@ -1021,20 +1343,20 @@ class MiawClient extends events_1.EventEmitter {
1021
1343
  async editMessage(message, newText) {
1022
1344
  try {
1023
1345
  if (!this.socket) {
1024
- throw new Error('Not connected. Call connect() first.');
1346
+ throw new Error("Not connected. Call connect() first.");
1025
1347
  }
1026
- if (this.connectionState !== 'connected') {
1348
+ if (this.connectionState !== "connected") {
1027
1349
  throw new Error(`Cannot edit message. Connection state: ${this.connectionState}`);
1028
1350
  }
1029
1351
  if (!message.raw?.key) {
1030
- throw new Error('Message does not contain raw Baileys key data. Cannot edit.');
1352
+ throw new Error("Message does not contain raw Baileys key data. Cannot edit.");
1031
1353
  }
1032
1354
  if (!message.fromMe) {
1033
- throw new Error('Can only edit your own messages.');
1355
+ throw new Error("Can only edit your own messages.");
1034
1356
  }
1035
1357
  const jid = message.raw.key.remoteJid;
1036
1358
  if (!jid) {
1037
- throw new Error('Message does not have a valid chat JID.');
1359
+ throw new Error("Message does not have a valid chat JID.");
1038
1360
  }
1039
1361
  const result = await this.socket.sendMessage(jid, {
1040
1362
  text: newText,
@@ -1046,7 +1368,7 @@ class MiawClient extends events_1.EventEmitter {
1046
1368
  };
1047
1369
  }
1048
1370
  catch (error) {
1049
- this.logger.error('Failed to edit message:', error);
1371
+ this.logger.error("Failed to edit message:", error);
1050
1372
  return {
1051
1373
  success: false,
1052
1374
  error: error.message,
@@ -1061,17 +1383,17 @@ class MiawClient extends events_1.EventEmitter {
1061
1383
  async deleteMessage(message) {
1062
1384
  try {
1063
1385
  if (!this.socket) {
1064
- throw new Error('Not connected. Call connect() first.');
1386
+ throw new Error("Not connected. Call connect() first.");
1065
1387
  }
1066
- if (this.connectionState !== 'connected') {
1388
+ if (this.connectionState !== "connected") {
1067
1389
  throw new Error(`Cannot delete message. Connection state: ${this.connectionState}`);
1068
1390
  }
1069
1391
  if (!message.raw?.key) {
1070
- throw new Error('Message does not contain raw Baileys key data. Cannot delete.');
1392
+ throw new Error("Message does not contain raw Baileys key data. Cannot delete.");
1071
1393
  }
1072
1394
  const jid = message.raw.key.remoteJid;
1073
1395
  if (!jid) {
1074
- throw new Error('Message does not have a valid chat JID.');
1396
+ throw new Error("Message does not have a valid chat JID.");
1075
1397
  }
1076
1398
  const result = await this.socket.sendMessage(jid, {
1077
1399
  delete: message.raw.key,
@@ -1082,7 +1404,7 @@ class MiawClient extends events_1.EventEmitter {
1082
1404
  };
1083
1405
  }
1084
1406
  catch (error) {
1085
- this.logger.error('Failed to delete message:', error);
1407
+ this.logger.error("Failed to delete message:", error);
1086
1408
  return {
1087
1409
  success: false,
1088
1410
  error: error.message,
@@ -1098,17 +1420,17 @@ class MiawClient extends events_1.EventEmitter {
1098
1420
  async deleteMessageForMe(message, deleteMedia = true) {
1099
1421
  try {
1100
1422
  if (!this.socket) {
1101
- throw new Error('Not connected. Call connect() first.');
1423
+ throw new Error("Not connected. Call connect() first.");
1102
1424
  }
1103
- if (this.connectionState !== 'connected') {
1425
+ if (this.connectionState !== "connected") {
1104
1426
  throw new Error(`Cannot delete message. Connection state: ${this.connectionState}`);
1105
1427
  }
1106
1428
  if (!message.raw?.key) {
1107
- throw new Error('Message does not contain raw Baileys key data. Cannot delete.');
1429
+ throw new Error("Message does not contain raw Baileys key data. Cannot delete.");
1108
1430
  }
1109
1431
  const jid = message.raw.key.remoteJid;
1110
1432
  if (!jid) {
1111
- throw new Error('Message does not have a valid chat JID.');
1433
+ throw new Error("Message does not have a valid chat JID.");
1112
1434
  }
1113
1435
  await this.socket.chatModify({
1114
1436
  deleteForMe: {
@@ -1120,7 +1442,7 @@ class MiawClient extends events_1.EventEmitter {
1120
1442
  return true;
1121
1443
  }
1122
1444
  catch (error) {
1123
- this.logger.error('Failed to delete message for me:', error);
1445
+ this.logger.error("Failed to delete message for me:", error);
1124
1446
  return false;
1125
1447
  }
1126
1448
  }
@@ -1135,19 +1457,19 @@ class MiawClient extends events_1.EventEmitter {
1135
1457
  async markAsRead(message) {
1136
1458
  try {
1137
1459
  if (!this.socket) {
1138
- throw new Error('Not connected. Call connect() first.');
1460
+ throw new Error("Not connected. Call connect() first.");
1139
1461
  }
1140
- if (this.connectionState !== 'connected') {
1462
+ if (this.connectionState !== "connected") {
1141
1463
  throw new Error(`Cannot mark as read. Connection state: ${this.connectionState}`);
1142
1464
  }
1143
1465
  if (!message.raw?.key) {
1144
- throw new Error('Message does not contain raw Baileys key data.');
1466
+ throw new Error("Message does not contain raw Baileys key data.");
1145
1467
  }
1146
1468
  await this.socket.readMessages([message.raw.key]);
1147
1469
  return true;
1148
1470
  }
1149
1471
  catch (error) {
1150
- this.logger.error('Failed to mark as read:', error);
1472
+ this.logger.error("Failed to mark as read:", error);
1151
1473
  return false;
1152
1474
  }
1153
1475
  }
@@ -1158,16 +1480,16 @@ class MiawClient extends events_1.EventEmitter {
1158
1480
  async sendTyping(to) {
1159
1481
  try {
1160
1482
  if (!this.socket) {
1161
- throw new Error('Not connected. Call connect() first.');
1483
+ throw new Error("Not connected. Call connect() first.");
1162
1484
  }
1163
- if (this.connectionState !== 'connected') {
1485
+ if (this.connectionState !== "connected") {
1164
1486
  throw new Error(`Cannot send typing. Connection state: ${this.connectionState}`);
1165
1487
  }
1166
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
1167
- await this.socket.sendPresenceUpdate('composing', jid);
1488
+ const jid = MessageHandler.formatPhoneToJid(to);
1489
+ await this.socket.sendPresenceUpdate("composing", jid);
1168
1490
  }
1169
1491
  catch (error) {
1170
- this.logger.error('Failed to send typing indicator:', error);
1492
+ this.logger.error("Failed to send typing indicator:", error);
1171
1493
  }
1172
1494
  }
1173
1495
  /**
@@ -1177,16 +1499,16 @@ class MiawClient extends events_1.EventEmitter {
1177
1499
  async sendRecording(to) {
1178
1500
  try {
1179
1501
  if (!this.socket) {
1180
- throw new Error('Not connected. Call connect() first.');
1502
+ throw new Error("Not connected. Call connect() first.");
1181
1503
  }
1182
- if (this.connectionState !== 'connected') {
1504
+ if (this.connectionState !== "connected") {
1183
1505
  throw new Error(`Cannot send recording. Connection state: ${this.connectionState}`);
1184
1506
  }
1185
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
1186
- await this.socket.sendPresenceUpdate('recording', jid);
1507
+ const jid = MessageHandler.formatPhoneToJid(to);
1508
+ await this.socket.sendPresenceUpdate("recording", jid);
1187
1509
  }
1188
1510
  catch (error) {
1189
- this.logger.error('Failed to send recording indicator:', error);
1511
+ this.logger.error("Failed to send recording indicator:", error);
1190
1512
  }
1191
1513
  }
1192
1514
  /**
@@ -1196,16 +1518,16 @@ class MiawClient extends events_1.EventEmitter {
1196
1518
  async stopTyping(to) {
1197
1519
  try {
1198
1520
  if (!this.socket) {
1199
- throw new Error('Not connected. Call connect() first.');
1521
+ throw new Error("Not connected. Call connect() first.");
1200
1522
  }
1201
- if (this.connectionState !== 'connected') {
1523
+ if (this.connectionState !== "connected") {
1202
1524
  throw new Error(`Cannot stop typing. Connection state: ${this.connectionState}`);
1203
1525
  }
1204
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(to);
1205
- await this.socket.sendPresenceUpdate('paused', jid);
1526
+ const jid = MessageHandler.formatPhoneToJid(to);
1527
+ await this.socket.sendPresenceUpdate("paused", jid);
1206
1528
  }
1207
1529
  catch (error) {
1208
- this.logger.error('Failed to stop typing indicator:', error);
1530
+ this.logger.error("Failed to stop typing indicator:", error);
1209
1531
  }
1210
1532
  }
1211
1533
  /**
@@ -1215,15 +1537,15 @@ class MiawClient extends events_1.EventEmitter {
1215
1537
  async setPresence(status) {
1216
1538
  try {
1217
1539
  if (!this.socket) {
1218
- throw new Error('Not connected. Call connect() first.');
1540
+ throw new Error("Not connected. Call connect() first.");
1219
1541
  }
1220
- if (this.connectionState !== 'connected') {
1542
+ if (this.connectionState !== "connected") {
1221
1543
  throw new Error(`Cannot set presence. Connection state: ${this.connectionState}`);
1222
1544
  }
1223
1545
  await this.socket.sendPresenceUpdate(status);
1224
1546
  }
1225
1547
  catch (error) {
1226
- this.logger.error('Failed to set presence:', error);
1548
+ this.logger.error("Failed to set presence:", error);
1227
1549
  }
1228
1550
  }
1229
1551
  /**
@@ -1234,16 +1556,16 @@ class MiawClient extends events_1.EventEmitter {
1234
1556
  async subscribePresence(jidOrPhone) {
1235
1557
  try {
1236
1558
  if (!this.socket) {
1237
- throw new Error('Not connected. Call connect() first.');
1559
+ throw new Error("Not connected. Call connect() first.");
1238
1560
  }
1239
- if (this.connectionState !== 'connected') {
1561
+ if (this.connectionState !== "connected") {
1240
1562
  throw new Error(`Cannot subscribe to presence. Connection state: ${this.connectionState}`);
1241
1563
  }
1242
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(jidOrPhone);
1564
+ const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
1243
1565
  await this.socket.presenceSubscribe(jid);
1244
1566
  }
1245
1567
  catch (error) {
1246
- this.logger.error('Failed to subscribe to presence:', error);
1568
+ this.logger.error("Failed to subscribe to presence:", error);
1247
1569
  }
1248
1570
  }
1249
1571
  // ============================================
@@ -1254,21 +1576,21 @@ class MiawClient extends events_1.EventEmitter {
1254
1576
  */
1255
1577
  async groupParticipantsOperation(groupJid, participants, action) {
1256
1578
  if (!this.socket) {
1257
- throw new Error('Not connected. Call connect() first.');
1579
+ throw new Error("Not connected. Call connect() first.");
1258
1580
  }
1259
- if (this.connectionState !== 'connected') {
1581
+ if (this.connectionState !== "connected") {
1260
1582
  throw new Error(`Cannot perform group operation. Connection state: ${this.connectionState}`);
1261
1583
  }
1262
- if (!groupJid.endsWith('@g.us')) {
1263
- throw new Error('Invalid group JID. Must end with @g.us');
1584
+ if (!groupJid.endsWith("@g.us")) {
1585
+ throw new Error("Invalid group JID. Must end with @g.us");
1264
1586
  }
1265
1587
  // Format participant JIDs
1266
- const formattedParticipants = participants.map((p) => MessageHandler_1.MessageHandler.formatPhoneToJid(p));
1588
+ const formattedParticipants = participants.map((p) => MessageHandler.formatPhoneToJid(p));
1267
1589
  const results = await this.socket.groupParticipantsUpdate(groupJid, formattedParticipants, action);
1268
1590
  return results.map((result) => ({
1269
- jid: result.jid || '',
1591
+ jid: result.jid || "",
1270
1592
  status: result.status,
1271
- success: result.status === '200',
1593
+ success: result.status === "200",
1272
1594
  }));
1273
1595
  }
1274
1596
  /**
@@ -1280,17 +1602,21 @@ class MiawClient extends events_1.EventEmitter {
1280
1602
  async createGroup(name, participants) {
1281
1603
  try {
1282
1604
  if (!this.socket) {
1283
- throw new Error('Not connected. Call connect() first.');
1605
+ throw new Error("Not connected. Call connect() first.");
1284
1606
  }
1285
- if (this.connectionState !== 'connected') {
1607
+ if (this.connectionState !== "connected") {
1286
1608
  throw new Error(`Cannot create group. Connection state: ${this.connectionState}`);
1287
1609
  }
1288
1610
  // Format participant JIDs
1289
- const formattedParticipants = participants.map((p) => MessageHandler_1.MessageHandler.formatPhoneToJid(p));
1611
+ const formattedParticipants = participants.map((p) => MessageHandler.formatPhoneToJid(p));
1290
1612
  const metadata = await this.socket.groupCreate(name, formattedParticipants);
1291
1613
  const groupParticipants = metadata.participants.map((p) => ({
1292
1614
  jid: p.id,
1293
- role: p.admin === 'superadmin' ? 'superadmin' : p.admin === 'admin' ? 'admin' : 'member',
1615
+ role: p.admin === "superadmin"
1616
+ ? "superadmin"
1617
+ : p.admin === "admin"
1618
+ ? "admin"
1619
+ : "member",
1294
1620
  }));
1295
1621
  return {
1296
1622
  success: true,
@@ -1309,7 +1635,7 @@ class MiawClient extends events_1.EventEmitter {
1309
1635
  };
1310
1636
  }
1311
1637
  catch (error) {
1312
- this.logger.error('Failed to create group:', error);
1638
+ this.logger.error("Failed to create group:", error);
1313
1639
  return {
1314
1640
  success: false,
1315
1641
  error: error.message,
@@ -1324,13 +1650,13 @@ class MiawClient extends events_1.EventEmitter {
1324
1650
  */
1325
1651
  async addParticipants(groupJid, participants) {
1326
1652
  try {
1327
- return await this.groupParticipantsOperation(groupJid, participants, 'add');
1653
+ return await this.groupParticipantsOperation(groupJid, participants, "add");
1328
1654
  }
1329
1655
  catch (error) {
1330
- this.logger.error('Failed to add participants:', error);
1656
+ this.logger.error("Failed to add participants:", error);
1331
1657
  return participants.map((p) => ({
1332
- jid: MessageHandler_1.MessageHandler.formatPhoneToJid(p),
1333
- status: 'error',
1658
+ jid: MessageHandler.formatPhoneToJid(p),
1659
+ status: "error",
1334
1660
  success: false,
1335
1661
  }));
1336
1662
  }
@@ -1343,13 +1669,13 @@ class MiawClient extends events_1.EventEmitter {
1343
1669
  */
1344
1670
  async removeParticipants(groupJid, participants) {
1345
1671
  try {
1346
- return await this.groupParticipantsOperation(groupJid, participants, 'remove');
1672
+ return await this.groupParticipantsOperation(groupJid, participants, "remove");
1347
1673
  }
1348
1674
  catch (error) {
1349
- this.logger.error('Failed to remove participants:', error);
1675
+ this.logger.error("Failed to remove participants:", error);
1350
1676
  return participants.map((p) => ({
1351
- jid: MessageHandler_1.MessageHandler.formatPhoneToJid(p),
1352
- status: 'error',
1677
+ jid: MessageHandler.formatPhoneToJid(p),
1678
+ status: "error",
1353
1679
  success: false,
1354
1680
  }));
1355
1681
  }
@@ -1362,19 +1688,19 @@ class MiawClient extends events_1.EventEmitter {
1362
1688
  async leaveGroup(groupJid) {
1363
1689
  try {
1364
1690
  if (!this.socket) {
1365
- throw new Error('Not connected. Call connect() first.');
1691
+ throw new Error("Not connected. Call connect() first.");
1366
1692
  }
1367
- if (this.connectionState !== 'connected') {
1693
+ if (this.connectionState !== "connected") {
1368
1694
  throw new Error(`Cannot leave group. Connection state: ${this.connectionState}`);
1369
1695
  }
1370
- if (!groupJid.endsWith('@g.us')) {
1371
- throw new Error('Invalid group JID. Must end with @g.us');
1696
+ if (!groupJid.endsWith("@g.us")) {
1697
+ throw new Error("Invalid group JID. Must end with @g.us");
1372
1698
  }
1373
1699
  await this.socket.groupLeave(groupJid);
1374
1700
  return { success: true };
1375
1701
  }
1376
1702
  catch (error) {
1377
- this.logger.error('Failed to leave group:', error);
1703
+ this.logger.error("Failed to leave group:", error);
1378
1704
  return {
1379
1705
  success: false,
1380
1706
  error: error.message,
@@ -1389,13 +1715,13 @@ class MiawClient extends events_1.EventEmitter {
1389
1715
  */
1390
1716
  async promoteToAdmin(groupJid, participants) {
1391
1717
  try {
1392
- return await this.groupParticipantsOperation(groupJid, participants, 'promote');
1718
+ return await this.groupParticipantsOperation(groupJid, participants, "promote");
1393
1719
  }
1394
1720
  catch (error) {
1395
- this.logger.error('Failed to promote participants:', error);
1721
+ this.logger.error("Failed to promote participants:", error);
1396
1722
  return participants.map((p) => ({
1397
- jid: MessageHandler_1.MessageHandler.formatPhoneToJid(p),
1398
- status: 'error',
1723
+ jid: MessageHandler.formatPhoneToJid(p),
1724
+ status: "error",
1399
1725
  success: false,
1400
1726
  }));
1401
1727
  }
@@ -1408,13 +1734,13 @@ class MiawClient extends events_1.EventEmitter {
1408
1734
  */
1409
1735
  async demoteFromAdmin(groupJid, participants) {
1410
1736
  try {
1411
- return await this.groupParticipantsOperation(groupJid, participants, 'demote');
1737
+ return await this.groupParticipantsOperation(groupJid, participants, "demote");
1412
1738
  }
1413
1739
  catch (error) {
1414
- this.logger.error('Failed to demote participants:', error);
1740
+ this.logger.error("Failed to demote participants:", error);
1415
1741
  return participants.map((p) => ({
1416
- jid: MessageHandler_1.MessageHandler.formatPhoneToJid(p),
1417
- status: 'error',
1742
+ jid: MessageHandler.formatPhoneToJid(p),
1743
+ status: "error",
1418
1744
  success: false,
1419
1745
  }));
1420
1746
  }
@@ -1428,19 +1754,19 @@ class MiawClient extends events_1.EventEmitter {
1428
1754
  async updateGroupName(groupJid, name) {
1429
1755
  try {
1430
1756
  if (!this.socket) {
1431
- throw new Error('Not connected. Call connect() first.');
1757
+ throw new Error("Not connected. Call connect() first.");
1432
1758
  }
1433
- if (this.connectionState !== 'connected') {
1759
+ if (this.connectionState !== "connected") {
1434
1760
  throw new Error(`Cannot update group name. Connection state: ${this.connectionState}`);
1435
1761
  }
1436
- if (!groupJid.endsWith('@g.us')) {
1437
- throw new Error('Invalid group JID. Must end with @g.us');
1762
+ if (!groupJid.endsWith("@g.us")) {
1763
+ throw new Error("Invalid group JID. Must end with @g.us");
1438
1764
  }
1439
1765
  await this.socket.groupUpdateSubject(groupJid, name);
1440
1766
  return { success: true };
1441
1767
  }
1442
1768
  catch (error) {
1443
- this.logger.error('Failed to update group name:', error);
1769
+ this.logger.error("Failed to update group name:", error);
1444
1770
  return {
1445
1771
  success: false,
1446
1772
  error: error.message,
@@ -1456,19 +1782,19 @@ class MiawClient extends events_1.EventEmitter {
1456
1782
  async updateGroupDescription(groupJid, description) {
1457
1783
  try {
1458
1784
  if (!this.socket) {
1459
- throw new Error('Not connected. Call connect() first.');
1785
+ throw new Error("Not connected. Call connect() first.");
1460
1786
  }
1461
- if (this.connectionState !== 'connected') {
1787
+ if (this.connectionState !== "connected") {
1462
1788
  throw new Error(`Cannot update group description. Connection state: ${this.connectionState}`);
1463
1789
  }
1464
- if (!groupJid.endsWith('@g.us')) {
1465
- throw new Error('Invalid group JID. Must end with @g.us');
1790
+ if (!groupJid.endsWith("@g.us")) {
1791
+ throw new Error("Invalid group JID. Must end with @g.us");
1466
1792
  }
1467
1793
  await this.socket.groupUpdateDescription(groupJid, description);
1468
1794
  return { success: true };
1469
1795
  }
1470
1796
  catch (error) {
1471
- this.logger.error('Failed to update group description:', error);
1797
+ this.logger.error("Failed to update group description:", error);
1472
1798
  return {
1473
1799
  success: false,
1474
1800
  error: error.message,
@@ -1484,20 +1810,20 @@ class MiawClient extends events_1.EventEmitter {
1484
1810
  async updateGroupPicture(groupJid, image) {
1485
1811
  try {
1486
1812
  if (!this.socket) {
1487
- throw new Error('Not connected. Call connect() first.');
1813
+ throw new Error("Not connected. Call connect() first.");
1488
1814
  }
1489
- if (this.connectionState !== 'connected') {
1815
+ if (this.connectionState !== "connected") {
1490
1816
  throw new Error(`Cannot update group picture. Connection state: ${this.connectionState}`);
1491
1817
  }
1492
- if (!groupJid.endsWith('@g.us')) {
1493
- throw new Error('Invalid group JID. Must end with @g.us');
1818
+ if (!groupJid.endsWith("@g.us")) {
1819
+ throw new Error("Invalid group JID. Must end with @g.us");
1494
1820
  }
1495
1821
  const imageContent = Buffer.isBuffer(image) ? image : { url: image };
1496
1822
  await this.socket.updateProfilePicture(groupJid, imageContent);
1497
1823
  return { success: true };
1498
1824
  }
1499
1825
  catch (error) {
1500
- this.logger.error('Failed to update group picture:', error);
1826
+ this.logger.error("Failed to update group picture:", error);
1501
1827
  return {
1502
1828
  success: false,
1503
1829
  error: error.message,
@@ -1512,19 +1838,19 @@ class MiawClient extends events_1.EventEmitter {
1512
1838
  async getGroupInviteLink(groupJid) {
1513
1839
  try {
1514
1840
  if (!this.socket) {
1515
- throw new Error('Not connected. Call connect() first.');
1841
+ throw new Error("Not connected. Call connect() first.");
1516
1842
  }
1517
- if (this.connectionState !== 'connected') {
1843
+ if (this.connectionState !== "connected") {
1518
1844
  throw new Error(`Cannot get invite link. Connection state: ${this.connectionState}`);
1519
1845
  }
1520
- if (!groupJid.endsWith('@g.us')) {
1521
- throw new Error('Invalid group JID. Must end with @g.us');
1846
+ if (!groupJid.endsWith("@g.us")) {
1847
+ throw new Error("Invalid group JID. Must end with @g.us");
1522
1848
  }
1523
1849
  const code = await this.socket.groupInviteCode(groupJid);
1524
1850
  return code ? `https://chat.whatsapp.com/${code}` : null;
1525
1851
  }
1526
1852
  catch (error) {
1527
- this.logger.error('Failed to get group invite link:', error);
1853
+ this.logger.error("Failed to get group invite link:", error);
1528
1854
  return null;
1529
1855
  }
1530
1856
  }
@@ -1536,19 +1862,19 @@ class MiawClient extends events_1.EventEmitter {
1536
1862
  async revokeGroupInvite(groupJid) {
1537
1863
  try {
1538
1864
  if (!this.socket) {
1539
- throw new Error('Not connected. Call connect() first.');
1865
+ throw new Error("Not connected. Call connect() first.");
1540
1866
  }
1541
- if (this.connectionState !== 'connected') {
1867
+ if (this.connectionState !== "connected") {
1542
1868
  throw new Error(`Cannot revoke invite. Connection state: ${this.connectionState}`);
1543
1869
  }
1544
- if (!groupJid.endsWith('@g.us')) {
1545
- throw new Error('Invalid group JID. Must end with @g.us');
1870
+ if (!groupJid.endsWith("@g.us")) {
1871
+ throw new Error("Invalid group JID. Must end with @g.us");
1546
1872
  }
1547
1873
  const code = await this.socket.groupRevokeInvite(groupJid);
1548
1874
  return code ? `https://chat.whatsapp.com/${code}` : null;
1549
1875
  }
1550
1876
  catch (error) {
1551
- this.logger.error('Failed to revoke group invite:', error);
1877
+ this.logger.error("Failed to revoke group invite:", error);
1552
1878
  return null;
1553
1879
  }
1554
1880
  }
@@ -1560,21 +1886,21 @@ class MiawClient extends events_1.EventEmitter {
1560
1886
  async acceptGroupInvite(inviteCode) {
1561
1887
  try {
1562
1888
  if (!this.socket) {
1563
- throw new Error('Not connected. Call connect() first.');
1889
+ throw new Error("Not connected. Call connect() first.");
1564
1890
  }
1565
- if (this.connectionState !== 'connected') {
1891
+ if (this.connectionState !== "connected") {
1566
1892
  throw new Error(`Cannot accept invite. Connection state: ${this.connectionState}`);
1567
1893
  }
1568
1894
  // Extract code from URL if full URL was provided
1569
1895
  let code = inviteCode;
1570
- if (inviteCode.includes('chat.whatsapp.com/')) {
1571
- code = inviteCode.split('chat.whatsapp.com/')[1];
1896
+ if (inviteCode.includes("chat.whatsapp.com/")) {
1897
+ code = inviteCode.split("chat.whatsapp.com/")[1];
1572
1898
  }
1573
1899
  const groupJid = await this.socket.groupAcceptInvite(code);
1574
1900
  return groupJid || null;
1575
1901
  }
1576
1902
  catch (error) {
1577
- this.logger.error('Failed to accept group invite:', error);
1903
+ this.logger.error("Failed to accept group invite:", error);
1578
1904
  return null;
1579
1905
  }
1580
1906
  }
@@ -1586,15 +1912,15 @@ class MiawClient extends events_1.EventEmitter {
1586
1912
  async getGroupInviteInfo(inviteCode) {
1587
1913
  try {
1588
1914
  if (!this.socket) {
1589
- throw new Error('Not connected. Call connect() first.');
1915
+ throw new Error("Not connected. Call connect() first.");
1590
1916
  }
1591
- if (this.connectionState !== 'connected') {
1917
+ if (this.connectionState !== "connected") {
1592
1918
  throw new Error(`Cannot get invite info. Connection state: ${this.connectionState}`);
1593
1919
  }
1594
1920
  // Extract code from URL if full URL was provided
1595
1921
  let code = inviteCode;
1596
- if (inviteCode.includes('chat.whatsapp.com/')) {
1597
- code = inviteCode.split('chat.whatsapp.com/')[1];
1922
+ if (inviteCode.includes("chat.whatsapp.com/")) {
1923
+ code = inviteCode.split("chat.whatsapp.com/")[1];
1598
1924
  }
1599
1925
  const metadata = await this.socket.groupGetInviteInfo(code);
1600
1926
  return {
@@ -1606,7 +1932,7 @@ class MiawClient extends events_1.EventEmitter {
1606
1932
  };
1607
1933
  }
1608
1934
  catch (error) {
1609
- this.logger.error('Failed to get group invite info:', error);
1935
+ this.logger.error("Failed to get group invite info:", error);
1610
1936
  return null;
1611
1937
  }
1612
1938
  }
@@ -1621,21 +1947,21 @@ class MiawClient extends events_1.EventEmitter {
1621
1947
  async updateProfilePicture(image) {
1622
1948
  try {
1623
1949
  if (!this.socket) {
1624
- throw new Error('Not connected. Call connect() first.');
1950
+ throw new Error("Not connected. Call connect() first.");
1625
1951
  }
1626
- if (this.connectionState !== 'connected') {
1952
+ if (this.connectionState !== "connected") {
1627
1953
  throw new Error(`Cannot update profile picture. Connection state: ${this.connectionState}`);
1628
1954
  }
1629
1955
  const userJid = this.socket.user?.id;
1630
1956
  if (!userJid) {
1631
- throw new Error('User JID not available');
1957
+ throw new Error("User JID not available");
1632
1958
  }
1633
1959
  const imageContent = Buffer.isBuffer(image) ? image : { url: image };
1634
1960
  await this.socket.updateProfilePicture(userJid, imageContent);
1635
1961
  return { success: true };
1636
1962
  }
1637
1963
  catch (error) {
1638
- this.logger.error('Failed to update profile picture:', error);
1964
+ this.logger.error("Failed to update profile picture:", error);
1639
1965
  return {
1640
1966
  success: false,
1641
1967
  error: error.message,
@@ -1649,20 +1975,20 @@ class MiawClient extends events_1.EventEmitter {
1649
1975
  async removeProfilePicture() {
1650
1976
  try {
1651
1977
  if (!this.socket) {
1652
- throw new Error('Not connected. Call connect() first.');
1978
+ throw new Error("Not connected. Call connect() first.");
1653
1979
  }
1654
- if (this.connectionState !== 'connected') {
1980
+ if (this.connectionState !== "connected") {
1655
1981
  throw new Error(`Cannot remove profile picture. Connection state: ${this.connectionState}`);
1656
1982
  }
1657
1983
  const userJid = this.socket.user?.id;
1658
1984
  if (!userJid) {
1659
- throw new Error('User JID not available');
1985
+ throw new Error("User JID not available");
1660
1986
  }
1661
1987
  await this.socket.removeProfilePicture(userJid);
1662
1988
  return { success: true };
1663
1989
  }
1664
1990
  catch (error) {
1665
- this.logger.error('Failed to remove profile picture:', error);
1991
+ this.logger.error("Failed to remove profile picture:", error);
1666
1992
  return {
1667
1993
  success: false,
1668
1994
  error: error.message,
@@ -1677,19 +2003,19 @@ class MiawClient extends events_1.EventEmitter {
1677
2003
  async updateProfileName(name) {
1678
2004
  try {
1679
2005
  if (!this.socket) {
1680
- throw new Error('Not connected. Call connect() first.');
2006
+ throw new Error("Not connected. Call connect() first.");
1681
2007
  }
1682
- if (this.connectionState !== 'connected') {
2008
+ if (this.connectionState !== "connected") {
1683
2009
  throw new Error(`Cannot update profile name. Connection state: ${this.connectionState}`);
1684
2010
  }
1685
2011
  if (!name || name.trim().length === 0) {
1686
- throw new Error('Profile name cannot be empty');
2012
+ throw new Error("Profile name cannot be empty");
1687
2013
  }
1688
2014
  await this.socket.updateProfileName(name);
1689
2015
  return { success: true };
1690
2016
  }
1691
2017
  catch (error) {
1692
- this.logger.error('Failed to update profile name:', error);
2018
+ this.logger.error("Failed to update profile name:", error);
1693
2019
  return {
1694
2020
  success: false,
1695
2021
  error: error.message,
@@ -1704,16 +2030,16 @@ class MiawClient extends events_1.EventEmitter {
1704
2030
  async updateProfileStatus(status) {
1705
2031
  try {
1706
2032
  if (!this.socket) {
1707
- throw new Error('Not connected. Call connect() first.');
2033
+ throw new Error("Not connected. Call connect() first.");
1708
2034
  }
1709
- if (this.connectionState !== 'connected') {
2035
+ if (this.connectionState !== "connected") {
1710
2036
  throw new Error(`Cannot update profile status. Connection state: ${this.connectionState}`);
1711
2037
  }
1712
2038
  await this.socket.updateProfileStatus(status);
1713
2039
  return { success: true };
1714
2040
  }
1715
2041
  catch (error) {
1716
- this.logger.error('Failed to update profile status:', error);
2042
+ this.logger.error("Failed to update profile status:", error);
1717
2043
  return {
1718
2044
  success: false,
1719
2045
  error: error.message,
@@ -1732,14 +2058,19 @@ class MiawClient extends events_1.EventEmitter {
1732
2058
  async addLabel(label) {
1733
2059
  try {
1734
2060
  if (!this.socket) {
1735
- throw new Error('Not connected. Call connect() first.');
2061
+ throw new Error("Not connected. Call connect() first.");
1736
2062
  }
1737
- if (this.connectionState !== 'connected') {
2063
+ if (this.connectionState !== "connected") {
1738
2064
  throw new Error(`Cannot add label. Connection state: ${this.connectionState}`);
1739
2065
  }
2066
+ // Generate a unique label ID if not provided
2067
+ // WhatsApp Business labels use numeric string IDs starting from 6 (1-5 are predefined)
2068
+ // We use timestamp + random suffix to ensure uniqueness
2069
+ const labelId = label.id ||
2070
+ `${Date.now().toString().slice(-8)}${Math.floor(Math.random() * 1000)}`;
1740
2071
  // Build label action body
1741
2072
  const labelAction = {
1742
- id: label.id,
2073
+ id: labelId,
1743
2074
  name: label.name,
1744
2075
  color: label.color,
1745
2076
  deleted: label.deleted ?? false,
@@ -1748,14 +2079,23 @@ class MiawClient extends events_1.EventEmitter {
1748
2079
  labelAction.predefinedId = label.predefinedId;
1749
2080
  }
1750
2081
  // Use empty string JID for label creation (affects account, not a specific chat)
1751
- await this.socket.addLabel('', labelAction);
2082
+ await this.socket.addLabel("", labelAction);
2083
+ // Store label in labelsStore immediately (don't wait for event)
2084
+ const labelData = {
2085
+ id: labelId,
2086
+ name: label.name,
2087
+ color: label.color,
2088
+ predefinedId: label.predefinedId,
2089
+ deleted: false,
2090
+ };
2091
+ this.labelsStore.set(labelId, labelData);
1752
2092
  return {
1753
2093
  success: true,
1754
- labelId: label.id,
2094
+ labelId: labelId,
1755
2095
  };
1756
2096
  }
1757
2097
  catch (error) {
1758
- this.logger.error('Failed to add label:', error);
2098
+ this.logger.error("Failed to add label:", error);
1759
2099
  return {
1760
2100
  success: false,
1761
2101
  error: error.message,
@@ -1772,17 +2112,17 @@ class MiawClient extends events_1.EventEmitter {
1772
2112
  async addChatLabel(chatJidOrPhone, labelId) {
1773
2113
  try {
1774
2114
  if (!this.socket) {
1775
- throw new Error('Not connected. Call connect() first.');
2115
+ throw new Error("Not connected. Call connect() first.");
1776
2116
  }
1777
- if (this.connectionState !== 'connected') {
2117
+ if (this.connectionState !== "connected") {
1778
2118
  throw new Error(`Cannot add chat label. Connection state: ${this.connectionState}`);
1779
2119
  }
1780
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(chatJidOrPhone);
2120
+ const jid = MessageHandler.formatPhoneToJid(chatJidOrPhone);
1781
2121
  await this.socket.addChatLabel(jid, labelId);
1782
2122
  return { success: true };
1783
2123
  }
1784
2124
  catch (error) {
1785
- this.logger.error('Failed to add chat label:', error);
2125
+ this.logger.error("Failed to add chat label:", error);
1786
2126
  return {
1787
2127
  success: false,
1788
2128
  error: error.message,
@@ -1799,17 +2139,17 @@ class MiawClient extends events_1.EventEmitter {
1799
2139
  async removeChatLabel(chatJidOrPhone, labelId) {
1800
2140
  try {
1801
2141
  if (!this.socket) {
1802
- throw new Error('Not connected. Call connect() first.');
2142
+ throw new Error("Not connected. Call connect() first.");
1803
2143
  }
1804
- if (this.connectionState !== 'connected') {
2144
+ if (this.connectionState !== "connected") {
1805
2145
  throw new Error(`Cannot remove chat label. Connection state: ${this.connectionState}`);
1806
2146
  }
1807
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(chatJidOrPhone);
2147
+ const jid = MessageHandler.formatPhoneToJid(chatJidOrPhone);
1808
2148
  await this.socket.removeChatLabel(jid, labelId);
1809
2149
  return { success: true };
1810
2150
  }
1811
2151
  catch (error) {
1812
- this.logger.error('Failed to remove chat label:', error);
2152
+ this.logger.error("Failed to remove chat label:", error);
1813
2153
  return {
1814
2154
  success: false,
1815
2155
  error: error.message,
@@ -1827,17 +2167,17 @@ class MiawClient extends events_1.EventEmitter {
1827
2167
  async addMessageLabel(chatJidOrPhone, messageId, labelId) {
1828
2168
  try {
1829
2169
  if (!this.socket) {
1830
- throw new Error('Not connected. Call connect() first.');
2170
+ throw new Error("Not connected. Call connect() first.");
1831
2171
  }
1832
- if (this.connectionState !== 'connected') {
2172
+ if (this.connectionState !== "connected") {
1833
2173
  throw new Error(`Cannot add message label. Connection state: ${this.connectionState}`);
1834
2174
  }
1835
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(chatJidOrPhone);
2175
+ const jid = MessageHandler.formatPhoneToJid(chatJidOrPhone);
1836
2176
  await this.socket.addMessageLabel(jid, messageId, labelId);
1837
2177
  return { success: true };
1838
2178
  }
1839
2179
  catch (error) {
1840
- this.logger.error('Failed to add message label:', error);
2180
+ this.logger.error("Failed to add message label:", error);
1841
2181
  return {
1842
2182
  success: false,
1843
2183
  error: error.message,
@@ -1855,17 +2195,17 @@ class MiawClient extends events_1.EventEmitter {
1855
2195
  async removeMessageLabel(chatJidOrPhone, messageId, labelId) {
1856
2196
  try {
1857
2197
  if (!this.socket) {
1858
- throw new Error('Not connected. Call connect() first.');
2198
+ throw new Error("Not connected. Call connect() first.");
1859
2199
  }
1860
- if (this.connectionState !== 'connected') {
2200
+ if (this.connectionState !== "connected") {
1861
2201
  throw new Error(`Cannot remove message label. Connection state: ${this.connectionState}`);
1862
2202
  }
1863
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(chatJidOrPhone);
2203
+ const jid = MessageHandler.formatPhoneToJid(chatJidOrPhone);
1864
2204
  await this.socket.removeMessageLabel(jid, messageId, labelId);
1865
2205
  return { success: true };
1866
2206
  }
1867
2207
  catch (error) {
1868
- this.logger.error('Failed to remove message label:', error);
2208
+ this.logger.error("Failed to remove message label:", error);
1869
2209
  return {
1870
2210
  success: false,
1871
2211
  error: error.message,
@@ -1881,28 +2221,32 @@ class MiawClient extends events_1.EventEmitter {
1881
2221
  * @param limit - Maximum number of products to fetch (default: 10)
1882
2222
  * @param cursor - Pagination cursor for fetching next page
1883
2223
  * @returns ProductCatalog
1884
- * @note Requires WhatsApp Business account
2224
+ * @note Requires WhatsApp Business account with catalog configured
1885
2225
  */
1886
2226
  async getCatalog(businessJidOrPhone, limit = 10, cursor) {
1887
2227
  try {
1888
2228
  if (!this.socket) {
1889
- throw new Error('Not connected. Call connect() first.');
2229
+ throw new Error("Not connected. Call connect() first.");
1890
2230
  }
1891
- if (this.connectionState !== 'connected') {
2231
+ if (this.connectionState !== "connected") {
1892
2232
  throw new Error(`Cannot get catalog. Connection state: ${this.connectionState}`);
1893
2233
  }
1894
- const jid = businessJidOrPhone ? MessageHandler_1.MessageHandler.formatPhoneToJid(businessJidOrPhone) : undefined;
2234
+ const jid = businessJidOrPhone
2235
+ ? MessageHandler.formatPhoneToJid(businessJidOrPhone)
2236
+ : undefined;
1895
2237
  const result = await this.socket.getCatalog({ jid, limit, cursor });
2238
+ // Map Baileys product format to our Product type
2239
+ // Baileys returns: id, name, description, price, currency, retailerId, url, isHidden, imageUrls
1896
2240
  const products = (result.products || []).map((p) => ({
1897
2241
  id: p.id,
1898
2242
  name: p.name,
1899
2243
  description: p.description,
1900
- priceAmount1000: p.priceAmount1000,
2244
+ price: p.price,
2245
+ currency: p.currency,
1901
2246
  retailerId: p.retailerId,
1902
2247
  url: p.url,
1903
2248
  isHidden: p.isHidden,
1904
- images: p.images?.map((img) => ({ url: img.url, caption: img.caption })) || [],
1905
- count: p.count,
2249
+ imageUrls: p.imageUrls || {},
1906
2250
  }));
1907
2251
  return {
1908
2252
  success: true,
@@ -1911,10 +2255,15 @@ class MiawClient extends events_1.EventEmitter {
1911
2255
  };
1912
2256
  }
1913
2257
  catch (error) {
1914
- this.logger.error('Failed to get catalog:', error);
2258
+ this.logger.error("Failed to get catalog:", error);
2259
+ // Provide more helpful error message
2260
+ const errorMsg = error.message;
2261
+ const helpfulError = errorMsg.includes("biz:catalog")
2262
+ ? "Catalog not available. Ensure this is a WhatsApp Business account with catalog enabled."
2263
+ : errorMsg;
1915
2264
  return {
1916
2265
  success: false,
1917
- error: error.message,
2266
+ error: helpfulError,
1918
2267
  };
1919
2268
  }
1920
2269
  }
@@ -1923,17 +2272,20 @@ class MiawClient extends events_1.EventEmitter {
1923
2272
  * @param businessJidOrPhone - Business JID or phone number (default: your own collections)
1924
2273
  * @param limit - Maximum number of collections to fetch (default: 51)
1925
2274
  * @returns Array of ProductCollection
1926
- * @note Requires WhatsApp Business account
2275
+ * @note Requires WhatsApp Business account with collections created via the catalog API.
2276
+ * Collections created in the WhatsApp Business app may not appear here.
1927
2277
  */
1928
2278
  async getCollections(businessJidOrPhone, limit = 51) {
1929
2279
  try {
1930
2280
  if (!this.socket) {
1931
- throw new Error('Not connected. Call connect() first.');
2281
+ throw new Error("Not connected. Call connect() first.");
1932
2282
  }
1933
- if (this.connectionState !== 'connected') {
2283
+ if (this.connectionState !== "connected") {
1934
2284
  throw new Error(`Cannot get collections. Connection state: ${this.connectionState}`);
1935
2285
  }
1936
- const jid = businessJidOrPhone ? MessageHandler_1.MessageHandler.formatPhoneToJid(businessJidOrPhone) : undefined;
2286
+ const jid = businessJidOrPhone
2287
+ ? MessageHandler.formatPhoneToJid(businessJidOrPhone)
2288
+ : undefined;
1937
2289
  const result = await this.socket.getCollections(jid, limit);
1938
2290
  return (result.collections || []).map((col) => ({
1939
2291
  id: col.id,
@@ -1943,48 +2295,59 @@ class MiawClient extends events_1.EventEmitter {
1943
2295
  name: p.name,
1944
2296
  priceAmount1000: p.priceAmount1000,
1945
2297
  retailerId: p.retailerId,
1946
- images: p.images?.map((img) => ({ url: img.url, caption: img.caption })) || [],
2298
+ images: p.images?.map((img) => ({
2299
+ url: img.url,
2300
+ caption: img.caption,
2301
+ })) || [],
1947
2302
  })),
1948
2303
  }));
1949
2304
  }
1950
2305
  catch (error) {
1951
- this.logger.error('Failed to get collections:', error);
2306
+ this.logger.error("Failed to get collections:", error);
1952
2307
  return [];
1953
2308
  }
1954
2309
  }
1955
2310
  /**
1956
2311
  * Create a new product in the catalog
1957
- * @param options - Product options (name, price, images, etc.)
2312
+ * @param options - Product options (name, price, currency, images, etc.)
1958
2313
  * @returns ProductOperationResult with product ID
1959
- * @note Requires WhatsApp Business account
2314
+ * @note Requires WhatsApp Business account with catalog enabled
1960
2315
  */
1961
2316
  async createProduct(options) {
1962
2317
  try {
1963
2318
  if (!this.socket) {
1964
- throw new Error('Not connected. Call connect() first.');
2319
+ throw new Error("Not connected. Call connect() first.");
1965
2320
  }
1966
- if (this.connectionState !== 'connected') {
2321
+ if (this.connectionState !== "connected") {
1967
2322
  throw new Error(`Cannot create product. Connection state: ${this.connectionState}`);
1968
2323
  }
1969
- // Convert price from smallest unit to Baileys format (multiply by 1000)
1970
- const priceAmount1000 = options.price * 10;
2324
+ // Build images array from either buffers or URLs
2325
+ // Buffers are recommended for reliability (URLs require WhatsApp servers to fetch)
2326
+ const images = [];
2327
+ // Prefer buffers if provided (more reliable)
2328
+ if (options.imageBuffers && options.imageBuffers.length > 0) {
2329
+ images.push(...options.imageBuffers);
2330
+ }
2331
+ else if (options.imageUrls && options.imageUrls.length > 0) {
2332
+ // Fall back to URLs (must be publicly accessible)
2333
+ images.push(...options.imageUrls.map((url) => ({ url: new URL(url) })));
2334
+ }
2335
+ // Build product data matching Baileys' ProductCreate format
1971
2336
  const productData = {
1972
2337
  name: options.name,
1973
- priceAmount1000,
2338
+ description: options.description,
2339
+ price: options.price,
2340
+ currency: options.currency,
1974
2341
  isHidden: options.isHidden ?? false,
2342
+ originCountryCode: options.originCountryCode,
2343
+ images,
1975
2344
  };
1976
- if (options.description) {
1977
- productData.description = options.description;
1978
- }
1979
2345
  if (options.retailerId) {
1980
2346
  productData.retailerId = options.retailerId;
1981
2347
  }
1982
2348
  if (options.url) {
1983
2349
  productData.url = options.url;
1984
2350
  }
1985
- if (options.imageUrls && options.imageUrls.length > 0) {
1986
- productData.images = options.imageUrls.map((url) => ({ url }));
1987
- }
1988
2351
  const result = await this.socket.productCreate(productData);
1989
2352
  return {
1990
2353
  success: true,
@@ -1992,7 +2355,7 @@ class MiawClient extends events_1.EventEmitter {
1992
2355
  };
1993
2356
  }
1994
2357
  catch (error) {
1995
- this.logger.error('Failed to create product:', error);
2358
+ this.logger.error("Failed to create product:", error);
1996
2359
  return {
1997
2360
  success: false,
1998
2361
  error: error.message,
@@ -2002,41 +2365,44 @@ class MiawClient extends events_1.EventEmitter {
2002
2365
  /**
2003
2366
  * Update an existing product in the catalog
2004
2367
  * @param productId - Product ID to update
2005
- * @param options - Product options (name, price, images, etc.)
2368
+ * @param options - Product options (name, price, currency, images, etc.)
2006
2369
  * @returns ProductOperationResult
2007
- * @note Requires WhatsApp Business account
2370
+ * @note Requires WhatsApp Business account with catalog enabled
2008
2371
  */
2009
2372
  async updateProduct(productId, options) {
2010
2373
  try {
2011
2374
  if (!this.socket) {
2012
- throw new Error('Not connected. Call connect() first.');
2375
+ throw new Error("Not connected. Call connect() first.");
2013
2376
  }
2014
- if (this.connectionState !== 'connected') {
2377
+ if (this.connectionState !== "connected") {
2015
2378
  throw new Error(`Cannot update product. Connection state: ${this.connectionState}`);
2016
2379
  }
2017
- // Convert price from smallest unit to Baileys format (multiply by 1000)
2018
- const priceAmount1000 = options.price * 10;
2019
- const productData = {
2020
- priceAmount1000,
2021
- };
2022
- if (options.name) {
2023
- productData.name = options.name;
2024
- }
2025
- if (options.description !== undefined) {
2026
- productData.description = options.description;
2380
+ // Build images array from either buffers or URLs
2381
+ // Buffers are recommended for reliability (URLs require WhatsApp servers to fetch)
2382
+ const images = [];
2383
+ // Prefer buffers if provided (more reliable)
2384
+ if (options.imageBuffers && options.imageBuffers.length > 0) {
2385
+ images.push(...options.imageBuffers);
2027
2386
  }
2028
- if (options.isHidden !== undefined) {
2029
- productData.isHidden = options.isHidden;
2387
+ else if (options.imageUrls && options.imageUrls.length > 0) {
2388
+ // Fall back to URLs (must be publicly accessible)
2389
+ images.push(...options.imageUrls.map((url) => ({ url: new URL(url) })));
2030
2390
  }
2391
+ // Build product data matching Baileys' ProductUpdate format
2392
+ const productData = {
2393
+ name: options.name,
2394
+ description: options.description,
2395
+ price: options.price,
2396
+ currency: options.currency,
2397
+ isHidden: options.isHidden,
2398
+ images,
2399
+ };
2031
2400
  if (options.retailerId) {
2032
2401
  productData.retailerId = options.retailerId;
2033
2402
  }
2034
2403
  if (options.url) {
2035
2404
  productData.url = options.url;
2036
2405
  }
2037
- if (options.imageUrls && options.imageUrls.length > 0) {
2038
- productData.images = options.imageUrls.map((url) => ({ url }));
2039
- }
2040
2406
  const result = await this.socket.productUpdate(productId, productData);
2041
2407
  return {
2042
2408
  success: true,
@@ -2044,7 +2410,7 @@ class MiawClient extends events_1.EventEmitter {
2044
2410
  };
2045
2411
  }
2046
2412
  catch (error) {
2047
- this.logger.error('Failed to update product:', error);
2413
+ this.logger.error("Failed to update product:", error);
2048
2414
  return {
2049
2415
  success: false,
2050
2416
  error: error.message,
@@ -2060,13 +2426,13 @@ class MiawClient extends events_1.EventEmitter {
2060
2426
  async deleteProducts(productIds) {
2061
2427
  try {
2062
2428
  if (!this.socket) {
2063
- throw new Error('Not connected. Call connect() first.');
2429
+ throw new Error("Not connected. Call connect() first.");
2064
2430
  }
2065
- if (this.connectionState !== 'connected') {
2431
+ if (this.connectionState !== "connected") {
2066
2432
  throw new Error(`Cannot delete products. Connection state: ${this.connectionState}`);
2067
2433
  }
2068
2434
  if (productIds.length === 0) {
2069
- throw new Error('At least one product ID is required');
2435
+ throw new Error("At least one product ID is required");
2070
2436
  }
2071
2437
  const result = await this.socket.productDelete(productIds);
2072
2438
  return {
@@ -2075,7 +2441,7 @@ class MiawClient extends events_1.EventEmitter {
2075
2441
  };
2076
2442
  }
2077
2443
  catch (error) {
2078
- this.logger.error('Failed to delete products:', error);
2444
+ this.logger.error("Failed to delete products:", error);
2079
2445
  return {
2080
2446
  success: false,
2081
2447
  error: error.message,
@@ -2085,6 +2451,113 @@ class MiawClient extends events_1.EventEmitter {
2085
2451
  // ============================================
2086
2452
  // Newsletter/Channel Methods (v0.9.0)
2087
2453
  // ============================================
2454
+ /**
2455
+ * Send a text message to a newsletter/channel
2456
+ * @param newsletterId - Newsletter JID (e.g., '1234567890@newsletter')
2457
+ * @param text - Message text content
2458
+ * @returns SendMessageResult
2459
+ * @note You must be an admin/owner of the newsletter to send messages
2460
+ */
2461
+ async sendNewsletterMessage(newsletterId, text) {
2462
+ try {
2463
+ if (!this.socket) {
2464
+ throw new Error("Not connected. Call connect() first.");
2465
+ }
2466
+ if (this.connectionState !== "connected") {
2467
+ throw new Error(`Cannot send newsletter message. Connection state: ${this.connectionState}`);
2468
+ }
2469
+ if (!newsletterId.endsWith("@newsletter")) {
2470
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2471
+ }
2472
+ // Baileys sendMessage handles newsletter JIDs automatically
2473
+ const result = await this.socket.sendMessage(newsletterId, { text });
2474
+ return {
2475
+ success: true,
2476
+ messageId: result?.key?.id ?? undefined,
2477
+ };
2478
+ }
2479
+ catch (error) {
2480
+ this.logger.error("Failed to send newsletter message:", error);
2481
+ return {
2482
+ success: false,
2483
+ error: error.message,
2484
+ };
2485
+ }
2486
+ }
2487
+ /**
2488
+ * Send an image to a newsletter/channel
2489
+ * @param newsletterId - Newsletter JID (e.g., '1234567890@newsletter')
2490
+ * @param image - Image source (file path, URL, or Buffer)
2491
+ * @param caption - Optional caption
2492
+ * @returns SendMessageResult
2493
+ * @note You must be an admin/owner of the newsletter to send messages
2494
+ */
2495
+ async sendNewsletterImage(newsletterId, image, caption) {
2496
+ try {
2497
+ if (!this.socket) {
2498
+ throw new Error("Not connected. Call connect() first.");
2499
+ }
2500
+ if (this.connectionState !== "connected") {
2501
+ throw new Error(`Cannot send newsletter image. Connection state: ${this.connectionState}`);
2502
+ }
2503
+ if (!newsletterId.endsWith("@newsletter")) {
2504
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2505
+ }
2506
+ const imageContent = Buffer.isBuffer(image) ? image : { url: image };
2507
+ const result = await this.socket.sendMessage(newsletterId, {
2508
+ image: imageContent,
2509
+ caption,
2510
+ });
2511
+ return {
2512
+ success: true,
2513
+ messageId: result?.key?.id ?? undefined,
2514
+ };
2515
+ }
2516
+ catch (error) {
2517
+ this.logger.error("Failed to send newsletter image:", error);
2518
+ return {
2519
+ success: false,
2520
+ error: error.message,
2521
+ };
2522
+ }
2523
+ }
2524
+ /**
2525
+ * Send a video to a newsletter/channel
2526
+ * @param newsletterId - Newsletter JID (e.g., '1234567890@newsletter')
2527
+ * @param video - Video source (file path, URL, or Buffer)
2528
+ * @param caption - Optional caption
2529
+ * @returns SendMessageResult
2530
+ * @note You must be an admin/owner of the newsletter to send messages
2531
+ */
2532
+ async sendNewsletterVideo(newsletterId, video, caption) {
2533
+ try {
2534
+ if (!this.socket) {
2535
+ throw new Error("Not connected. Call connect() first.");
2536
+ }
2537
+ if (this.connectionState !== "connected") {
2538
+ throw new Error(`Cannot send newsletter video. Connection state: ${this.connectionState}`);
2539
+ }
2540
+ if (!newsletterId.endsWith("@newsletter")) {
2541
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2542
+ }
2543
+ const videoContent = Buffer.isBuffer(video) ? video : { url: video };
2544
+ const result = await this.socket.sendMessage(newsletterId, {
2545
+ video: videoContent,
2546
+ caption,
2547
+ });
2548
+ return {
2549
+ success: true,
2550
+ messageId: result?.key?.id ?? undefined,
2551
+ };
2552
+ }
2553
+ catch (error) {
2554
+ this.logger.error("Failed to send newsletter video:", error);
2555
+ return {
2556
+ success: false,
2557
+ error: error.message,
2558
+ };
2559
+ }
2560
+ }
2088
2561
  /**
2089
2562
  * Create a new newsletter/channel
2090
2563
  * @param name - Newsletter name
@@ -2094,22 +2567,56 @@ class MiawClient extends events_1.EventEmitter {
2094
2567
  async createNewsletter(name, description) {
2095
2568
  try {
2096
2569
  if (!this.socket) {
2097
- throw new Error('Not connected. Call connect() first.');
2570
+ throw new Error("Not connected. Call connect() first.");
2098
2571
  }
2099
- if (this.connectionState !== 'connected') {
2572
+ if (this.connectionState !== "connected") {
2100
2573
  throw new Error(`Cannot create newsletter. Connection state: ${this.connectionState}`);
2101
2574
  }
2102
- const result = await this.socket.newsletterCreate(name, description || '');
2575
+ // Baileys newsletterCreate returns NewsletterMetadata with id property
2576
+ const result = await this.socket.newsletterCreate(name, description || "");
2577
+ // Debug log the result structure
2578
+ this.logger.debug("Newsletter create result:", result);
2579
+ // Baileys returns NewsletterMetadata from parseNewsletterCreateResponse
2580
+ // The id is directly on the result object
2581
+ if (result && typeof result === "object" && "id" in result) {
2582
+ const newsletterId = result.id;
2583
+ if (newsletterId) {
2584
+ return {
2585
+ success: true,
2586
+ newsletterId,
2587
+ };
2588
+ }
2589
+ }
2590
+ // Handle unexpected response format
2591
+ // The newsletter may have been created but response parsing failed
2592
+ this.logger.warn("Newsletter creation returned unexpected format:", JSON.stringify(result, null, 2));
2103
2593
  return {
2104
2594
  success: true,
2105
- newsletterId: result?.id,
2595
+ newsletterId: undefined,
2106
2596
  };
2107
2597
  }
2108
2598
  catch (error) {
2109
- this.logger.error('Failed to create newsletter:', error);
2599
+ const errorMessage = error.message;
2600
+ const errorStack = error.stack;
2601
+ // Log full error for debugging
2602
+ this.logger.debug("Newsletter creation error details:", {
2603
+ message: errorMessage,
2604
+ stack: errorStack,
2605
+ });
2606
+ // Check if this is a response parsing error (newsletter may have been created)
2607
+ // Baileys throws "Cannot read properties of null" when response format is unexpected
2608
+ if (errorMessage.includes("Cannot read properties of null") ||
2609
+ errorMessage.includes("Cannot read properties of undefined")) {
2610
+ this.logger.warn("Newsletter may have been created but response parsing failed:", errorMessage);
2611
+ return {
2612
+ success: true,
2613
+ newsletterId: undefined,
2614
+ };
2615
+ }
2616
+ this.logger.error("Failed to create newsletter:", error);
2110
2617
  return {
2111
2618
  success: false,
2112
- error: error.message,
2619
+ error: errorMessage,
2113
2620
  };
2114
2621
  }
2115
2622
  }
@@ -2121,23 +2628,23 @@ class MiawClient extends events_1.EventEmitter {
2121
2628
  async getNewsletterMetadata(newsletterId) {
2122
2629
  try {
2123
2630
  if (!this.socket) {
2124
- throw new Error('Not connected. Call connect() first.');
2631
+ throw new Error("Not connected. Call connect() first.");
2125
2632
  }
2126
- if (this.connectionState !== 'connected') {
2633
+ if (this.connectionState !== "connected") {
2127
2634
  throw new Error(`Cannot get newsletter metadata. Connection state: ${this.connectionState}`);
2128
2635
  }
2129
- if (!newsletterId.endsWith('@newsletter')) {
2130
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2636
+ if (!newsletterId.endsWith("@newsletter")) {
2637
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2131
2638
  }
2132
- const meta = await this.socket.newsletterMetadata('jid', newsletterId);
2639
+ const meta = await this.socket.newsletterMetadata("jid", newsletterId);
2133
2640
  if (!meta) {
2134
2641
  return null;
2135
2642
  }
2136
2643
  // Extract picture URL from the picture object if available
2137
- const pictureUrl = typeof meta.picture === 'string' ? meta.picture : meta.picture?.url;
2644
+ const pictureUrl = typeof meta.picture === "string" ? meta.picture : meta.picture?.url;
2138
2645
  return {
2139
2646
  id: meta.id || newsletterId,
2140
- name: meta.name || '',
2647
+ name: meta.name || "",
2141
2648
  description: meta.description,
2142
2649
  pictureUrl,
2143
2650
  subscribers: meta.subscribers,
@@ -2149,7 +2656,7 @@ class MiawClient extends events_1.EventEmitter {
2149
2656
  };
2150
2657
  }
2151
2658
  catch (error) {
2152
- this.logger.error('Failed to get newsletter metadata:', error);
2659
+ this.logger.error("Failed to get newsletter metadata:", error);
2153
2660
  return null;
2154
2661
  }
2155
2662
  }
@@ -2161,19 +2668,19 @@ class MiawClient extends events_1.EventEmitter {
2161
2668
  async followNewsletter(newsletterId) {
2162
2669
  try {
2163
2670
  if (!this.socket) {
2164
- throw new Error('Not connected. Call connect() first.');
2671
+ throw new Error("Not connected. Call connect() first.");
2165
2672
  }
2166
- if (this.connectionState !== 'connected') {
2673
+ if (this.connectionState !== "connected") {
2167
2674
  throw new Error(`Cannot follow newsletter. Connection state: ${this.connectionState}`);
2168
2675
  }
2169
- if (!newsletterId.endsWith('@newsletter')) {
2170
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2676
+ if (!newsletterId.endsWith("@newsletter")) {
2677
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2171
2678
  }
2172
2679
  await this.socket.newsletterFollow(newsletterId);
2173
2680
  return true;
2174
2681
  }
2175
2682
  catch (error) {
2176
- this.logger.error('Failed to follow newsletter:', error);
2683
+ this.logger.error("Failed to follow newsletter:", error);
2177
2684
  return false;
2178
2685
  }
2179
2686
  }
@@ -2185,19 +2692,19 @@ class MiawClient extends events_1.EventEmitter {
2185
2692
  async unfollowNewsletter(newsletterId) {
2186
2693
  try {
2187
2694
  if (!this.socket) {
2188
- throw new Error('Not connected. Call connect() first.');
2695
+ throw new Error("Not connected. Call connect() first.");
2189
2696
  }
2190
- if (this.connectionState !== 'connected') {
2697
+ if (this.connectionState !== "connected") {
2191
2698
  throw new Error(`Cannot unfollow newsletter. Connection state: ${this.connectionState}`);
2192
2699
  }
2193
- if (!newsletterId.endsWith('@newsletter')) {
2194
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2700
+ if (!newsletterId.endsWith("@newsletter")) {
2701
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2195
2702
  }
2196
2703
  await this.socket.newsletterUnfollow(newsletterId);
2197
2704
  return true;
2198
2705
  }
2199
2706
  catch (error) {
2200
- this.logger.error('Failed to unfollow newsletter:', error);
2707
+ this.logger.error("Failed to unfollow newsletter:", error);
2201
2708
  return false;
2202
2709
  }
2203
2710
  }
@@ -2209,19 +2716,19 @@ class MiawClient extends events_1.EventEmitter {
2209
2716
  async muteNewsletter(newsletterId) {
2210
2717
  try {
2211
2718
  if (!this.socket) {
2212
- throw new Error('Not connected. Call connect() first.');
2719
+ throw new Error("Not connected. Call connect() first.");
2213
2720
  }
2214
- if (this.connectionState !== 'connected') {
2721
+ if (this.connectionState !== "connected") {
2215
2722
  throw new Error(`Cannot mute newsletter. Connection state: ${this.connectionState}`);
2216
2723
  }
2217
- if (!newsletterId.endsWith('@newsletter')) {
2218
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2724
+ if (!newsletterId.endsWith("@newsletter")) {
2725
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2219
2726
  }
2220
2727
  await this.socket.newsletterMute(newsletterId);
2221
2728
  return true;
2222
2729
  }
2223
2730
  catch (error) {
2224
- this.logger.error('Failed to mute newsletter:', error);
2731
+ this.logger.error("Failed to mute newsletter:", error);
2225
2732
  return false;
2226
2733
  }
2227
2734
  }
@@ -2233,19 +2740,19 @@ class MiawClient extends events_1.EventEmitter {
2233
2740
  async unmuteNewsletter(newsletterId) {
2234
2741
  try {
2235
2742
  if (!this.socket) {
2236
- throw new Error('Not connected. Call connect() first.');
2743
+ throw new Error("Not connected. Call connect() first.");
2237
2744
  }
2238
- if (this.connectionState !== 'connected') {
2745
+ if (this.connectionState !== "connected") {
2239
2746
  throw new Error(`Cannot unmute newsletter. Connection state: ${this.connectionState}`);
2240
2747
  }
2241
- if (!newsletterId.endsWith('@newsletter')) {
2242
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2748
+ if (!newsletterId.endsWith("@newsletter")) {
2749
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2243
2750
  }
2244
2751
  await this.socket.newsletterUnmute(newsletterId);
2245
2752
  return true;
2246
2753
  }
2247
2754
  catch (error) {
2248
- this.logger.error('Failed to unmute newsletter:', error);
2755
+ this.logger.error("Failed to unmute newsletter:", error);
2249
2756
  return false;
2250
2757
  }
2251
2758
  }
@@ -2258,19 +2765,19 @@ class MiawClient extends events_1.EventEmitter {
2258
2765
  async updateNewsletterName(newsletterId, name) {
2259
2766
  try {
2260
2767
  if (!this.socket) {
2261
- throw new Error('Not connected. Call connect() first.');
2768
+ throw new Error("Not connected. Call connect() first.");
2262
2769
  }
2263
- if (this.connectionState !== 'connected') {
2770
+ if (this.connectionState !== "connected") {
2264
2771
  throw new Error(`Cannot update newsletter name. Connection state: ${this.connectionState}`);
2265
2772
  }
2266
- if (!newsletterId.endsWith('@newsletter')) {
2267
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2773
+ if (!newsletterId.endsWith("@newsletter")) {
2774
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2268
2775
  }
2269
2776
  await this.socket.newsletterUpdateName(newsletterId, name);
2270
2777
  return true;
2271
2778
  }
2272
2779
  catch (error) {
2273
- this.logger.error('Failed to update newsletter name:', error);
2780
+ this.logger.error("Failed to update newsletter name:", error);
2274
2781
  return false;
2275
2782
  }
2276
2783
  }
@@ -2283,19 +2790,19 @@ class MiawClient extends events_1.EventEmitter {
2283
2790
  async updateNewsletterDescription(newsletterId, description) {
2284
2791
  try {
2285
2792
  if (!this.socket) {
2286
- throw new Error('Not connected. Call connect() first.');
2793
+ throw new Error("Not connected. Call connect() first.");
2287
2794
  }
2288
- if (this.connectionState !== 'connected') {
2795
+ if (this.connectionState !== "connected") {
2289
2796
  throw new Error(`Cannot update newsletter description. Connection state: ${this.connectionState}`);
2290
2797
  }
2291
- if (!newsletterId.endsWith('@newsletter')) {
2292
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2798
+ if (!newsletterId.endsWith("@newsletter")) {
2799
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2293
2800
  }
2294
2801
  await this.socket.newsletterUpdateDescription(newsletterId, description);
2295
2802
  return true;
2296
2803
  }
2297
2804
  catch (error) {
2298
- this.logger.error('Failed to update newsletter description:', error);
2805
+ this.logger.error("Failed to update newsletter description:", error);
2299
2806
  return false;
2300
2807
  }
2301
2808
  }
@@ -2308,20 +2815,20 @@ class MiawClient extends events_1.EventEmitter {
2308
2815
  async updateNewsletterPicture(newsletterId, image) {
2309
2816
  try {
2310
2817
  if (!this.socket) {
2311
- throw new Error('Not connected. Call connect() first.');
2818
+ throw new Error("Not connected. Call connect() first.");
2312
2819
  }
2313
- if (this.connectionState !== 'connected') {
2820
+ if (this.connectionState !== "connected") {
2314
2821
  throw new Error(`Cannot update newsletter picture. Connection state: ${this.connectionState}`);
2315
2822
  }
2316
- if (!newsletterId.endsWith('@newsletter')) {
2317
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2823
+ if (!newsletterId.endsWith("@newsletter")) {
2824
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2318
2825
  }
2319
2826
  const imageContent = Buffer.isBuffer(image) ? image : { url: image };
2320
2827
  await this.socket.newsletterUpdatePicture(newsletterId, imageContent);
2321
2828
  return true;
2322
2829
  }
2323
2830
  catch (error) {
2324
- this.logger.error('Failed to update newsletter picture:', error);
2831
+ this.logger.error("Failed to update newsletter picture:", error);
2325
2832
  return false;
2326
2833
  }
2327
2834
  }
@@ -2333,19 +2840,19 @@ class MiawClient extends events_1.EventEmitter {
2333
2840
  async removeNewsletterPicture(newsletterId) {
2334
2841
  try {
2335
2842
  if (!this.socket) {
2336
- throw new Error('Not connected. Call connect() first.');
2843
+ throw new Error("Not connected. Call connect() first.");
2337
2844
  }
2338
- if (this.connectionState !== 'connected') {
2845
+ if (this.connectionState !== "connected") {
2339
2846
  throw new Error(`Cannot remove newsletter picture. Connection state: ${this.connectionState}`);
2340
2847
  }
2341
- if (!newsletterId.endsWith('@newsletter')) {
2342
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2848
+ if (!newsletterId.endsWith("@newsletter")) {
2849
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2343
2850
  }
2344
2851
  await this.socket.newsletterRemovePicture(newsletterId);
2345
2852
  return true;
2346
2853
  }
2347
2854
  catch (error) {
2348
- this.logger.error('Failed to remove newsletter picture:', error);
2855
+ this.logger.error("Failed to remove newsletter picture:", error);
2349
2856
  return false;
2350
2857
  }
2351
2858
  }
@@ -2359,19 +2866,19 @@ class MiawClient extends events_1.EventEmitter {
2359
2866
  async reactToNewsletterMessage(newsletterId, messageId, emoji) {
2360
2867
  try {
2361
2868
  if (!this.socket) {
2362
- throw new Error('Not connected. Call connect() first.');
2869
+ throw new Error("Not connected. Call connect() first.");
2363
2870
  }
2364
- if (this.connectionState !== 'connected') {
2871
+ if (this.connectionState !== "connected") {
2365
2872
  throw new Error(`Cannot react to newsletter message. Connection state: ${this.connectionState}`);
2366
2873
  }
2367
- if (!newsletterId.endsWith('@newsletter')) {
2368
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2874
+ if (!newsletterId.endsWith("@newsletter")) {
2875
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2369
2876
  }
2370
2877
  await this.socket.newsletterReactMessage(newsletterId, messageId, emoji);
2371
2878
  return true;
2372
2879
  }
2373
2880
  catch (error) {
2374
- this.logger.error('Failed to react to newsletter message:', error);
2881
+ this.logger.error("Failed to react to newsletter message:", error);
2375
2882
  return false;
2376
2883
  }
2377
2884
  }
@@ -2386,22 +2893,26 @@ class MiawClient extends events_1.EventEmitter {
2386
2893
  async fetchNewsletterMessages(newsletterId, count = 50, since, after = 0) {
2387
2894
  try {
2388
2895
  if (!this.socket) {
2389
- throw new Error('Not connected. Call connect() first.');
2896
+ throw new Error("Not connected. Call connect() first.");
2390
2897
  }
2391
- if (this.connectionState !== 'connected') {
2898
+ if (this.connectionState !== "connected") {
2392
2899
  throw new Error(`Cannot fetch newsletter messages. Connection state: ${this.connectionState}`);
2393
2900
  }
2394
- if (!newsletterId.endsWith('@newsletter')) {
2395
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2901
+ if (!newsletterId.endsWith("@newsletter")) {
2902
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2396
2903
  }
2397
2904
  const messages = await this.socket.newsletterFetchMessages(newsletterId, count, since || Date.now(), after);
2398
2905
  const normalizedMessages = (messages || []).map((msg) => ({
2399
- id: msg.key?.id || '',
2906
+ id: msg.key?.id || "",
2400
2907
  newsletterId,
2401
2908
  content: msg.message?.conversation || msg.message?.extendedTextMessage?.text,
2402
2909
  timestamp: msg.messageTimestamp || 0,
2403
2910
  mediaUrl: msg.message?.imageMessage?.url || msg.message?.videoMessage?.url,
2404
- mediaType: msg.message?.imageMessage ? 'image' : msg.message?.videoMessage ? 'video' : undefined,
2911
+ mediaType: msg.message?.imageMessage
2912
+ ? "image"
2913
+ : msg.message?.videoMessage
2914
+ ? "video"
2915
+ : undefined,
2405
2916
  }));
2406
2917
  return {
2407
2918
  success: true,
@@ -2409,7 +2920,7 @@ class MiawClient extends events_1.EventEmitter {
2409
2920
  };
2410
2921
  }
2411
2922
  catch (error) {
2412
- this.logger.error('Failed to fetch newsletter messages:', error);
2923
+ this.logger.error("Failed to fetch newsletter messages:", error);
2413
2924
  return {
2414
2925
  success: false,
2415
2926
  error: error.message,
@@ -2424,19 +2935,19 @@ class MiawClient extends events_1.EventEmitter {
2424
2935
  async subscribeNewsletterUpdates(newsletterId) {
2425
2936
  try {
2426
2937
  if (!this.socket) {
2427
- throw new Error('Not connected. Call connect() first.');
2938
+ throw new Error("Not connected. Call connect() first.");
2428
2939
  }
2429
- if (this.connectionState !== 'connected') {
2940
+ if (this.connectionState !== "connected") {
2430
2941
  throw new Error(`Cannot subscribe to newsletter updates. Connection state: ${this.connectionState}`);
2431
2942
  }
2432
- if (!newsletterId.endsWith('@newsletter')) {
2433
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2943
+ if (!newsletterId.endsWith("@newsletter")) {
2944
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2434
2945
  }
2435
2946
  await this.socket.subscribeNewsletterUpdates(newsletterId);
2436
2947
  return true;
2437
2948
  }
2438
2949
  catch (error) {
2439
- this.logger.error('Failed to subscribe to newsletter updates:', error);
2950
+ this.logger.error("Failed to subscribe to newsletter updates:", error);
2440
2951
  return false;
2441
2952
  }
2442
2953
  }
@@ -2448,13 +2959,13 @@ class MiawClient extends events_1.EventEmitter {
2448
2959
  async getNewsletterSubscribers(newsletterId) {
2449
2960
  try {
2450
2961
  if (!this.socket) {
2451
- throw new Error('Not connected. Call connect() first.');
2962
+ throw new Error("Not connected. Call connect() first.");
2452
2963
  }
2453
- if (this.connectionState !== 'connected') {
2964
+ if (this.connectionState !== "connected") {
2454
2965
  throw new Error(`Cannot get newsletter subscribers. Connection state: ${this.connectionState}`);
2455
2966
  }
2456
- if (!newsletterId.endsWith('@newsletter')) {
2457
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2967
+ if (!newsletterId.endsWith("@newsletter")) {
2968
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2458
2969
  }
2459
2970
  const result = await this.socket.newsletterSubscribers(newsletterId);
2460
2971
  return {
@@ -2463,7 +2974,7 @@ class MiawClient extends events_1.EventEmitter {
2463
2974
  };
2464
2975
  }
2465
2976
  catch (error) {
2466
- this.logger.error('Failed to get newsletter subscribers:', error);
2977
+ this.logger.error("Failed to get newsletter subscribers:", error);
2467
2978
  return null;
2468
2979
  }
2469
2980
  }
@@ -2475,19 +2986,19 @@ class MiawClient extends events_1.EventEmitter {
2475
2986
  async getNewsletterAdminCount(newsletterId) {
2476
2987
  try {
2477
2988
  if (!this.socket) {
2478
- throw new Error('Not connected. Call connect() first.');
2989
+ throw new Error("Not connected. Call connect() first.");
2479
2990
  }
2480
- if (this.connectionState !== 'connected') {
2991
+ if (this.connectionState !== "connected") {
2481
2992
  throw new Error(`Cannot get newsletter admin count. Connection state: ${this.connectionState}`);
2482
2993
  }
2483
- if (!newsletterId.endsWith('@newsletter')) {
2484
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
2994
+ if (!newsletterId.endsWith("@newsletter")) {
2995
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2485
2996
  }
2486
2997
  const count = await this.socket.newsletterAdminCount(newsletterId);
2487
2998
  return count || 0;
2488
2999
  }
2489
3000
  catch (error) {
2490
- this.logger.error('Failed to get newsletter admin count:', error);
3001
+ this.logger.error("Failed to get newsletter admin count:", error);
2491
3002
  return null;
2492
3003
  }
2493
3004
  }
@@ -2500,20 +3011,20 @@ class MiawClient extends events_1.EventEmitter {
2500
3011
  async changeNewsletterOwner(newsletterId, newOwnerJid) {
2501
3012
  try {
2502
3013
  if (!this.socket) {
2503
- throw new Error('Not connected. Call connect() first.');
3014
+ throw new Error("Not connected. Call connect() first.");
2504
3015
  }
2505
- if (this.connectionState !== 'connected') {
3016
+ if (this.connectionState !== "connected") {
2506
3017
  throw new Error(`Cannot change newsletter owner. Connection state: ${this.connectionState}`);
2507
3018
  }
2508
- if (!newsletterId.endsWith('@newsletter')) {
2509
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
3019
+ if (!newsletterId.endsWith("@newsletter")) {
3020
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2510
3021
  }
2511
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(newOwnerJid);
3022
+ const jid = MessageHandler.formatPhoneToJid(newOwnerJid);
2512
3023
  await this.socket.newsletterChangeOwner(newsletterId, jid);
2513
3024
  return true;
2514
3025
  }
2515
3026
  catch (error) {
2516
- this.logger.error('Failed to change newsletter owner:', error);
3027
+ this.logger.error("Failed to change newsletter owner:", error);
2517
3028
  return false;
2518
3029
  }
2519
3030
  }
@@ -2526,20 +3037,20 @@ class MiawClient extends events_1.EventEmitter {
2526
3037
  async demoteNewsletterAdmin(newsletterId, adminJid) {
2527
3038
  try {
2528
3039
  if (!this.socket) {
2529
- throw new Error('Not connected. Call connect() first.');
3040
+ throw new Error("Not connected. Call connect() first.");
2530
3041
  }
2531
- if (this.connectionState !== 'connected') {
3042
+ if (this.connectionState !== "connected") {
2532
3043
  throw new Error(`Cannot demote newsletter admin. Connection state: ${this.connectionState}`);
2533
3044
  }
2534
- if (!newsletterId.endsWith('@newsletter')) {
2535
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
3045
+ if (!newsletterId.endsWith("@newsletter")) {
3046
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2536
3047
  }
2537
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(adminJid);
3048
+ const jid = MessageHandler.formatPhoneToJid(adminJid);
2538
3049
  await this.socket.newsletterDemote(newsletterId, jid);
2539
3050
  return true;
2540
3051
  }
2541
3052
  catch (error) {
2542
- this.logger.error('Failed to demote newsletter admin:', error);
3053
+ this.logger.error("Failed to demote newsletter admin:", error);
2543
3054
  return false;
2544
3055
  }
2545
3056
  }
@@ -2551,19 +3062,19 @@ class MiawClient extends events_1.EventEmitter {
2551
3062
  async deleteNewsletter(newsletterId) {
2552
3063
  try {
2553
3064
  if (!this.socket) {
2554
- throw new Error('Not connected. Call connect() first.');
3065
+ throw new Error("Not connected. Call connect() first.");
2555
3066
  }
2556
- if (this.connectionState !== 'connected') {
3067
+ if (this.connectionState !== "connected") {
2557
3068
  throw new Error(`Cannot delete newsletter. Connection state: ${this.connectionState}`);
2558
3069
  }
2559
- if (!newsletterId.endsWith('@newsletter')) {
2560
- throw new Error('Invalid newsletter ID. Must end with @newsletter');
3070
+ if (!newsletterId.endsWith("@newsletter")) {
3071
+ throw new Error("Invalid newsletter ID. Must end with @newsletter");
2561
3072
  }
2562
3073
  await this.socket.newsletterDelete(newsletterId);
2563
3074
  return true;
2564
3075
  }
2565
3076
  catch (error) {
2566
- this.logger.error('Failed to delete newsletter:', error);
3077
+ this.logger.error("Failed to delete newsletter:", error);
2567
3078
  return false;
2568
3079
  }
2569
3080
  }
@@ -2578,12 +3089,12 @@ class MiawClient extends events_1.EventEmitter {
2578
3089
  async addOrEditContact(contact) {
2579
3090
  try {
2580
3091
  if (!this.socket) {
2581
- throw new Error('Not connected. Call connect() first.');
3092
+ throw new Error("Not connected. Call connect() first.");
2582
3093
  }
2583
- if (this.connectionState !== 'connected') {
3094
+ if (this.connectionState !== "connected") {
2584
3095
  throw new Error(`Cannot add/edit contact. Connection state: ${this.connectionState}`);
2585
3096
  }
2586
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(contact.phone);
3097
+ const jid = MessageHandler.formatPhoneToJid(contact.phone);
2587
3098
  // Build contact action for Baileys
2588
3099
  const contactAction = {
2589
3100
  displayName: contact.name,
@@ -2598,7 +3109,7 @@ class MiawClient extends events_1.EventEmitter {
2598
3109
  return { success: true };
2599
3110
  }
2600
3111
  catch (error) {
2601
- this.logger.error('Failed to add/edit contact:', error);
3112
+ this.logger.error("Failed to add/edit contact:", error);
2602
3113
  return {
2603
3114
  success: false,
2604
3115
  error: error.message,
@@ -2613,17 +3124,17 @@ class MiawClient extends events_1.EventEmitter {
2613
3124
  async removeContact(phone) {
2614
3125
  try {
2615
3126
  if (!this.socket) {
2616
- throw new Error('Not connected. Call connect() first.');
3127
+ throw new Error("Not connected. Call connect() first.");
2617
3128
  }
2618
- if (this.connectionState !== 'connected') {
3129
+ if (this.connectionState !== "connected") {
2619
3130
  throw new Error(`Cannot remove contact. Connection state: ${this.connectionState}`);
2620
3131
  }
2621
- const jid = MessageHandler_1.MessageHandler.formatPhoneToJid(phone);
3132
+ const jid = MessageHandler.formatPhoneToJid(phone);
2622
3133
  await this.socket.removeContact(jid);
2623
3134
  return { success: true };
2624
3135
  }
2625
3136
  catch (error) {
2626
- this.logger.error('Failed to remove contact:', error);
3137
+ this.logger.error("Failed to remove contact:", error);
2627
3138
  return {
2628
3139
  success: false,
2629
3140
  error: error.message,
@@ -2636,16 +3147,16 @@ class MiawClient extends events_1.EventEmitter {
2636
3147
  getAudioMimetypeFromFileName(fileName) {
2637
3148
  const ext = path.extname(fileName).toLowerCase();
2638
3149
  const mimeTypes = {
2639
- '.mp3': 'audio/mpeg',
2640
- '.mp4': 'audio/mp4',
2641
- '.m4a': 'audio/mp4',
2642
- '.ogg': 'audio/ogg; codecs=opus',
2643
- '.opus': 'audio/ogg; codecs=opus',
2644
- '.wav': 'audio/wav',
2645
- '.aac': 'audio/aac',
2646
- '.flac': 'audio/flac',
3150
+ ".mp3": "audio/mpeg",
3151
+ ".mp4": "audio/mp4",
3152
+ ".m4a": "audio/mp4",
3153
+ ".ogg": "audio/ogg; codecs=opus",
3154
+ ".opus": "audio/ogg; codecs=opus",
3155
+ ".wav": "audio/wav",
3156
+ ".aac": "audio/aac",
3157
+ ".flac": "audio/flac",
2647
3158
  };
2648
- return mimeTypes[ext] || 'audio/mp4';
3159
+ return mimeTypes[ext] || "audio/mp4";
2649
3160
  }
2650
3161
  /**
2651
3162
  * Get MIME type from file extension
@@ -2653,24 +3164,24 @@ class MiawClient extends events_1.EventEmitter {
2653
3164
  getMimetypeFromFileName(fileName) {
2654
3165
  const ext = path.extname(fileName).toLowerCase();
2655
3166
  const mimeTypes = {
2656
- '.pdf': 'application/pdf',
2657
- '.doc': 'application/msword',
2658
- '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2659
- '.xls': 'application/vnd.ms-excel',
2660
- '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2661
- '.ppt': 'application/vnd.ms-powerpoint',
2662
- '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2663
- '.txt': 'text/plain',
2664
- '.csv': 'text/csv',
2665
- '.json': 'application/json',
2666
- '.xml': 'application/xml',
2667
- '.zip': 'application/zip',
2668
- '.rar': 'application/x-rar-compressed',
2669
- '.7z': 'application/x-7z-compressed',
2670
- '.tar': 'application/x-tar',
2671
- '.gz': 'application/gzip',
3167
+ ".pdf": "application/pdf",
3168
+ ".doc": "application/msword",
3169
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
3170
+ ".xls": "application/vnd.ms-excel",
3171
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
3172
+ ".ppt": "application/vnd.ms-powerpoint",
3173
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
3174
+ ".txt": "text/plain",
3175
+ ".csv": "text/csv",
3176
+ ".json": "application/json",
3177
+ ".xml": "application/xml",
3178
+ ".zip": "application/zip",
3179
+ ".rar": "application/x-rar-compressed",
3180
+ ".7z": "application/x-7z-compressed",
3181
+ ".tar": "application/x-tar",
3182
+ ".gz": "application/gzip",
2672
3183
  };
2673
- return mimeTypes[ext] || 'application/octet-stream';
3184
+ return mimeTypes[ext] || "application/octet-stream";
2674
3185
  }
2675
3186
  /**
2676
3187
  * Disconnect from WhatsApp
@@ -2684,8 +3195,8 @@ class MiawClient extends events_1.EventEmitter {
2684
3195
  await this.socket.logout();
2685
3196
  this.socket = null;
2686
3197
  }
2687
- this.updateConnectionState('disconnected');
2688
- this.logger.info('Disconnected');
3198
+ this.updateConnectionState("disconnected");
3199
+ this.logger.info("Disconnected");
2689
3200
  }
2690
3201
  /**
2691
3202
  * Get current connection state
@@ -2703,7 +3214,7 @@ class MiawClient extends events_1.EventEmitter {
2703
3214
  * Check if connected
2704
3215
  */
2705
3216
  isConnected() {
2706
- return this.connectionState === 'connected';
3217
+ return this.connectionState === "connected";
2707
3218
  }
2708
3219
  // TypeScript event emitter type safety
2709
3220
  on(event, listener) {
@@ -2713,5 +3224,4 @@ class MiawClient extends events_1.EventEmitter {
2713
3224
  return super.emit(event, ...args);
2714
3225
  }
2715
3226
  }
2716
- exports.MiawClient = MiawClient;
2717
3227
  //# sourceMappingURL=MiawClient.js.map