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