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