wa-multi-mongodb 3.9.5 → 3.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { WASocket } from "baileys";
2
- import type { MessageReceived, MessageUpdated, StartSessionParams, StartSessionWithPairingCodeParams } from "../Types";
2
+ import type { MessageReceived, MessageUpdated, StartSessionParams } from "../Types";
3
3
  /**
4
4
  * Set MongoDB URI for connection
5
5
  * This function will be used to configure MongoDB connection with just the URI
@@ -10,10 +10,15 @@ export declare const setMongoURI: (uri: string) => Promise<void>;
10
10
  export declare function setMongoCollection(collection: any): void;
11
11
  export declare const startSession: (sessionId?: string, options?: StartSessionParams) => Promise<WASocket>;
12
12
  /**
13
+ * Start WhatsApp session using pairing code method
14
+ * This is the recommended way to create sessions with pairing code
13
15
  *
14
- * @deprecated Use startSession method instead
16
+ * @param sessionId Unique session identifier
17
+ * @param phoneNumber Phone number with country code (without + prefix)
18
+ * @param options Optional configuration for the session
19
+ * @returns Promise<WASocket> The WhatsApp socket instance
15
20
  */
16
- export declare const startSessionWithPairingCode: (sessionId: string, options: StartSessionWithPairingCodeParams) => Promise<WASocket>;
21
+ export declare const startSessionWithPairingCode: (sessionId: string, phoneNumber: string, options?: StartSessionParams) => Promise<WASocket>;
17
22
  /**
18
23
  * @deprecated Use startSession method instead
19
24
  */
@@ -65,6 +70,30 @@ export declare const setCredentialsDir: (dirname?: string) => void;
65
70
  * @returns Promise<boolean> indicating success
66
71
  */
67
72
  export declare const reconnect: (sessionId: string) => Promise<boolean>;
73
+ /**
74
+ * Reconnect all pairing code sessions that are tracked
75
+ * Useful for bulk reconnection after system restart
76
+ */
77
+ export declare const reconnectAllPairingCodeSessions: () => Promise<{
78
+ [sessionId: string]: boolean;
79
+ }>;
80
+ /**
81
+ * Get all tracked pairing code sessions
82
+ * @returns Array of session IDs that were created with pairing code
83
+ */
84
+ export declare const getPairingCodeSessions: () => string[];
85
+ /**
86
+ * Get session status information
87
+ * @param sessionId Session ID to check
88
+ * @returns Object with session status information
89
+ */
90
+ export declare const getSessionStatus: (sessionId: string) => {
91
+ sessionId: string;
92
+ isRunning: boolean;
93
+ isPairingCodeSession: boolean;
94
+ retryAttempts: number;
95
+ hasCredentials: boolean;
96
+ };
68
97
  export declare const setGroupCacheConfig: (options: {
69
98
  stdTTL?: number;
70
99
  checkperiod?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Socket/index.ts"],"names":[],"mappings":"AAAA,OAAqB,EAInB,QAAQ,EACT,MAAM,SAAS,CAAC;AAKjB,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iCAAiC,EAClC,MAAM,UAAU,CAAC;AA8BlB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAU,KAAK,MAAM,kBAkB5C,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,GAAG,QAEjD;AAkBD,eAAO,MAAM,YAAY,GACvB,kBAAuB,EACvB,UAAS,kBAAsC,KAC9C,OAAO,CAAC,QAAQ,CAkIlB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,GACtC,WAAW,MAAM,EACjB,SAAS,iCAAiC,KACzC,OAAO,CAAC,QAAQ,CAuGlB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,iCAxPf,kBAAkB,KAC1B,OAAO,CAAC,QAAQ,CAuPsB,CAAC;AAE1C,eAAO,MAAM,aAAa,GAAU,WAAW,MAAM,kBAkCpD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,MAAM,EAAE,CAsBtD,CAAC;AAGF,eAAO,MAAM,iBAAiB,QAAO,MAAM,EAAiC,CAAC;AAE7E,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,QAAQ,GAAG,SACrB,CAAC;AAoChC;;GAEG;AACH,eAAO,MAAM,uBAAuB,YAMnC,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,UAAU,CAAC,GAAG,EAAE,eAAe,KAAK,GAAG,SAExE,CAAC;AACF,eAAO,MAAM,WAAW,GACtB,UAAU,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,KAAK,GAAG,SAGxE,CAAC;AACF,eAAO,MAAM,WAAW,GAAI,UAAU,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,SAE/D,CAAC;AACF,eAAO,MAAM,cAAc,GAAI,UAAU,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,SAElE,CAAC;AACF,eAAO,MAAM,YAAY,GAAI,UAAU,CAAC,SAAS,EAAE,MAAM,KAAK,GAAG,SAEhE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,UAAU,CAAC,IAAI,EAAE,cAAc,KAAK,GAAG,SAEtE,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,SAGnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,qBAcjC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,SAAQ,MAAqB,EAAE,iBAAgB,MAAe,SAI7F,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAS,MAAyB,SAGnE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,OAAO,CAsDlE,CAAC;AAGF,eAAO,MAAM,mBAAmB,GAAI,SAAS;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,SAEA,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,KAAK,MAAM,EACX,aAAY,OAAe,KAC1B,OAAO,CAAC,GAAG,CA4Bb,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAU,WAAW,MAAM,EAAE,KAAK,MAAM,kBAE3E,CAAC;AAGF,eAAO,MAAM,8BAA8B,GAAU,WAAW,MAAM,kBAErE,CAAC;AAGF,eAAO,MAAM,0BAA0B,YAEtC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Socket/index.ts"],"names":[],"mappings":"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"}
@@ -45,7 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.clearAllGroupMetadataCache = exports.clearSessionGroupMetadataCache = exports.clearGroupMetadataCache = exports.getGroupMetadata = exports.setGroupCacheConfig = exports.reconnect = exports.setCredentialsDir = exports.setMongoDBNames = exports.loadSessionsFromMongo = exports.onPairingCode = exports.onMessageUpdate = exports.onConnecting = exports.onDisconnected = exports.onConnected = exports.onQRUpdated = exports.onMessageReceived = exports.loadSessionsFromStorage = exports.getSession = exports.getAllSessionSync = exports.getAllSession = exports.deleteSession = exports.startWhatsapp = exports.startSessionWithPairingCode = exports.startSession = exports.setMongoURI = void 0;
48
+ exports.clearAllGroupMetadataCache = exports.clearSessionGroupMetadataCache = exports.clearGroupMetadataCache = exports.getGroupMetadata = exports.setGroupCacheConfig = exports.getSessionStatus = exports.getPairingCodeSessions = exports.reconnectAllPairingCodeSessions = exports.reconnect = exports.setCredentialsDir = exports.setMongoDBNames = exports.loadSessionsFromMongo = exports.onPairingCode = exports.onMessageUpdate = exports.onConnecting = exports.onDisconnected = exports.onConnected = exports.onQRUpdated = exports.onMessageReceived = exports.loadSessionsFromStorage = exports.getSession = exports.getAllSessionSync = exports.getAllSession = exports.deleteSession = exports.startWhatsapp = exports.startSessionWithPairingCode = exports.startSession = exports.setMongoURI = void 0;
49
49
  exports.setMongoCollection = setMongoCollection;
50
50
  const baileys_1 = __importStar(require("baileys"));
51
51
  const path_1 = __importDefault(require("path"));
@@ -62,6 +62,8 @@ const create_delay_1 = require("../Utils/create-delay");
62
62
  const sessions = new Map();
63
63
  const callback = new Map();
64
64
  const retryCount = new Map();
65
+ // Tambahkan Map untuk melacak session yang menggunakan pairing code
66
+ const pairingCodeSessions = new Map();
65
67
  const P = require("pino")({
66
68
  level: "silent",
67
69
  });
@@ -90,7 +92,7 @@ const setMongoURI = (uri) => __awaiter(void 0, void 0, void 0, function* () {
90
92
  mongoClient = undefined;
91
93
  authCollection = null;
92
94
  }
93
- console.log("MongoDB URI configured successfully");
95
+ // MongoDB URI configured successfully - removed console.log for npm package
94
96
  });
95
97
  exports.setMongoURI = setMongoURI;
96
98
  function setMongoCollection(collection) {
@@ -137,6 +139,7 @@ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, funct
137
139
  const update = events["connection.update"];
138
140
  const { connection, lastDisconnect } = update;
139
141
  if (update.qr) {
142
+ // Print QR to console if requested
140
143
  if (options.printQR) {
141
144
  qrcode_1.default.toString(update.qr, {
142
145
  type: 'terminal',
@@ -148,9 +151,10 @@ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, funct
148
151
  }
149
152
  });
150
153
  }
154
+ // Send QR data raw to callback for frontend processing
151
155
  (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_QR)) === null || _a === void 0 ? void 0 : _a({
152
156
  sessionId,
153
- qr: update.qr,
157
+ qr: update.qr
154
158
  });
155
159
  (_b = options.onQRUpdated) === null || _b === void 0 ? void 0 : _b.call(options, update.qr);
156
160
  }
@@ -172,7 +176,14 @@ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, funct
172
176
  }
173
177
  else {
174
178
  retryCount.delete(sessionId);
175
- (0, exports.deleteSession)(sessionId);
179
+ // For pairing code sessions, preserve data for future reconnection
180
+ if (pairingCodeSessions.has(sessionId)) {
181
+ yield softDeleteSession(sessionId, true);
182
+ }
183
+ else {
184
+ // For regular sessions, completely delete
185
+ yield softDeleteSession(sessionId, false);
186
+ }
176
187
  (_h = callback.get(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED)) === null || _h === void 0 ? void 0 : _h(sessionId);
177
188
  (_j = options.onDisconnected) === null || _j === void 0 ? void 0 : _j.call(options);
178
189
  }
@@ -219,15 +230,25 @@ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, funct
219
230
  (_o = options.onMessageUpdated) === null || _o === void 0 ? void 0 : _o.call(options, data);
220
231
  }
221
232
  if (events["messages.upsert"]) {
222
- const msg = (_p = events["messages.upsert"]
223
- .messages) === null || _p === void 0 ? void 0 : _p[0];
224
- msg.sessionId = sessionId;
225
- msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
226
- msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
227
- msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
228
- msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
229
- (_q = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _q === void 0 ? void 0 : _q(Object.assign({}, msg));
230
- (_r = options.onMessageReceived) === null || _r === void 0 ? void 0 : _r.call(options, msg);
233
+ const messages = events["messages.upsert"].messages || [];
234
+ for (const rawMsg of messages) {
235
+ // Skip protocol messages and system messages
236
+ if ((_p = rawMsg.message) === null || _p === void 0 ? void 0 : _p.protocolMessage) {
237
+ continue;
238
+ }
239
+ // Skip messages without content
240
+ if (!rawMsg.message || Object.keys(rawMsg.message).length === 0) {
241
+ continue;
242
+ }
243
+ const msg = rawMsg;
244
+ msg.sessionId = sessionId;
245
+ msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
246
+ msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
247
+ msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
248
+ msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
249
+ (_q = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _q === void 0 ? void 0 : _q(Object.assign({}, msg));
250
+ (_r = options.onMessageReceived) === null || _r === void 0 ? void 0 : _r.call(options, msg);
251
+ }
231
252
  }
232
253
  }));
233
254
  return sock;
@@ -241,16 +262,23 @@ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, funct
241
262
  });
242
263
  exports.startSession = startSession;
243
264
  /**
265
+ * Start WhatsApp session using pairing code method
266
+ * This is the recommended way to create sessions with pairing code
244
267
  *
245
- * @deprecated Use startSession method instead
268
+ * @param sessionId Unique session identifier
269
+ * @param phoneNumber Phone number with country code (without + prefix)
270
+ * @param options Optional configuration for the session
271
+ * @returns Promise<WASocket> The WhatsApp socket instance
246
272
  */
247
- const startSessionWithPairingCode = (sessionId, options) => __awaiter(void 0, void 0, void 0, function* () {
273
+ const startSessionWithPairingCode = (sessionId_1, phoneNumber_1, ...args_1) => __awaiter(void 0, [sessionId_1, phoneNumber_1, ...args_1], void 0, function* (sessionId, phoneNumber, options = {}) {
248
274
  if (isSessionExistAndRunning(sessionId))
249
275
  throw new Error_1.WhatsappError(Defaults_1.Messages.sessionAlreadyExist(sessionId));
276
+ // Simpan informasi session pairing code untuk auto-reconnect
277
+ pairingCodeSessions.set(sessionId, { phoneNumber, options });
250
278
  yield initMongo();
251
279
  const { version } = yield (0, baileys_1.fetchLatestBaileysVersion)();
252
280
  const startSocket = () => __awaiter(void 0, void 0, void 0, function* () {
253
- var _a;
281
+ var _a, _b;
254
282
  const { state, saveCreds } = yield (0, mongo_auth_state_1.useMongoAuthState)(sessionId, authCollection);
255
283
  const sock = (0, baileys_1.default)({
256
284
  version,
@@ -258,80 +286,172 @@ const startSessionWithPairingCode = (sessionId, options) => __awaiter(void 0, vo
258
286
  logger: P,
259
287
  markOnlineOnConnect: false,
260
288
  browser: baileys_1.Browsers.ubuntu("Chrome"),
289
+ // Opsi tambahan untuk meningkatkan kompatibilitas
290
+ linkPreviewImageThumbnailWidth: 300,
291
+ generateHighQualityLinkPreview: true,
292
+ syncFullHistory: false, // Sinkronisasi hanya riwayat baru
293
+ connectTimeoutMs: 60000, // Timeout koneksi ditingkatkan
294
+ printQRInTerminal: false, // QR tidak dicetak untuk pairing code
295
+ // Configure caching group metadata using our hybrid implementation with session ID
296
+ cachedGroupMetadata: (jid) => __awaiter(void 0, void 0, void 0, function* () {
297
+ return yield Utils_1.groupCache.get(sessionId, jid);
298
+ })
261
299
  });
262
300
  sessions.set(sessionId, Object.assign({}, sock));
263
301
  try {
264
302
  if (!sock.authState.creds.registered) {
265
- console.log("first time pairing");
266
- const code = yield sock.requestPairingCode(options.phoneNumber);
267
- console.log(code);
268
- (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE)) === null || _a === void 0 ? void 0 : _a(sessionId, code);
303
+ // Pastikan kita mendapatkan kode pairing dan menampilkannya dengan jelas
304
+ try {
305
+ // Tambahkan delay untuk memastikan state sudah siap
306
+ yield new Promise(resolve => setTimeout(resolve, 2000));
307
+ // Hapus awalan + dari nomor telepon jika ada
308
+ const phoneNumberFormatted = phoneNumber.replace(/^\+/, '');
309
+ // Memanggil fungsi requestPairingCode dengan nomor telepon yang sudah dibersihkan
310
+ const code = yield sock.requestPairingCode(phoneNumberFormatted);
311
+ // Pastikan kode ada dan merupakan string
312
+ if (code && typeof code === 'string') {
313
+ console.log(`Pairing code untuk session ${sessionId}: ${code}`);
314
+ // Panggil callback yang terdaftar
315
+ (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE)) === null || _a === void 0 ? void 0 : _a(sessionId, code);
316
+ (_b = options.onPairingCode) === null || _b === void 0 ? void 0 : _b.call(options, code);
317
+ }
318
+ else {
319
+ console.error("Error: Kode pairing tidak valid atau kosong");
320
+ }
321
+ }
322
+ catch (error) {
323
+ console.error("Error saat meminta kode pairing:", error);
324
+ throw new Error_1.WhatsappError(`Gagal mendapatkan kode pairing: ${error.message || String(error)}`);
325
+ }
269
326
  }
270
327
  sock.ev.process((events) => __awaiter(void 0, void 0, void 0, function* () {
271
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
328
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
272
329
  if (events["connection.update"]) {
273
330
  const update = events["connection.update"];
274
331
  const { connection, lastDisconnect } = update;
275
332
  if (update.qr) {
276
- qrcode_1.default.toString(update.qr, {
277
- type: 'terminal',
278
- small: true,
279
- margin: 1
280
- }, (err, qrString) => {
281
- if (!err) {
282
- console.log(qrString);
283
- }
284
- });
333
+ // Send QR data raw to callback for frontend processing
285
334
  (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_QR)) === null || _a === void 0 ? void 0 : _a({
286
335
  sessionId,
287
- qr: update.qr,
336
+ qr: update.qr
288
337
  });
289
338
  }
290
339
  if (connection == "connecting") {
291
340
  (_b = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTING)) === null || _b === void 0 ? void 0 : _b(sessionId);
341
+ (_c = options.onConnecting) === null || _c === void 0 ? void 0 : _c.call(options);
292
342
  }
293
343
  if (connection === "close") {
294
- const code = (_d = (_c = lastDisconnect === null || lastDisconnect === void 0 ? void 0 : lastDisconnect.error) === null || _c === void 0 ? void 0 : _c.output) === null || _d === void 0 ? void 0 : _d.statusCode;
295
- let retryAttempt = (_e = retryCount.get(sessionId)) !== null && _e !== void 0 ? _e : 0;
344
+ const code = (_e = (_d = lastDisconnect === null || lastDisconnect === void 0 ? void 0 : lastDisconnect.error) === null || _d === void 0 ? void 0 : _d.output) === null || _e === void 0 ? void 0 : _e.statusCode;
345
+ let retryAttempt = (_f = retryCount.get(sessionId)) !== null && _f !== void 0 ? _f : 0;
296
346
  let shouldRetry;
297
347
  if (code != baileys_1.DisconnectReason.loggedOut && retryAttempt < 10) {
298
348
  shouldRetry = true;
299
349
  }
300
350
  if (shouldRetry) {
301
351
  retryAttempt++;
302
- }
303
- if (shouldRetry) {
304
352
  retryCount.set(sessionId, retryAttempt);
305
- startSocket();
353
+ // Untuk session pairing code, coba reconnect dengan metode yang tepat
354
+ try {
355
+ // Tunggu sebentar sebelum reconnect
356
+ yield (0, create_delay_1.createDelay)(2000);
357
+ startSocket();
358
+ }
359
+ catch (reconnectError) {
360
+ console.error(`Auto-reconnect failed for session ${sessionId}:`, reconnectError.message);
361
+ // Jika reconnect gagal beberapa kali, coba dengan pairing code lagi (jika masih dalam 3 attempt pertama)
362
+ if (retryAttempt <= 3 && pairingCodeSessions.has(sessionId)) {
363
+ const sessionInfo = pairingCodeSessions.get(sessionId);
364
+ // Bersihkan session lama
365
+ sessions.delete(sessionId);
366
+ // Coba mulai ulang dengan pairing code baru
367
+ setTimeout(() => {
368
+ startSocket().catch(err => {
369
+ console.error(`Failed to restart with pairing code for session ${sessionId}:`, err);
370
+ });
371
+ }, 3000);
372
+ }
373
+ else {
374
+ // Jika sudah terlalu banyak gagal, panggil startSocket biasa
375
+ startSocket();
376
+ }
377
+ }
306
378
  }
307
379
  else {
308
380
  retryCount.delete(sessionId);
309
- (0, exports.deleteSession)(sessionId);
310
- (_f = callback.get(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED)) === null || _f === void 0 ? void 0 : _f(sessionId);
381
+ // For pairing code sessions, preserve data for future reconnection
382
+ if (pairingCodeSessions.has(sessionId)) {
383
+ yield softDeleteSession(sessionId, true);
384
+ // Don't remove from pairing code tracking completely to allow manual reconnection
385
+ }
386
+ else {
387
+ pairingCodeSessions.delete(sessionId); // Only delete from tracking if it's not a pairing code session
388
+ yield softDeleteSession(sessionId, false);
389
+ }
390
+ (_g = callback.get(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED)) === null || _g === void 0 ? void 0 : _g(sessionId);
391
+ (_h = options.onDisconnected) === null || _h === void 0 ? void 0 : _h.call(options);
311
392
  }
312
393
  }
313
394
  if (connection == "open") {
314
395
  retryCount.delete(sessionId);
315
- (_g = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTED)) === null || _g === void 0 ? void 0 : _g(sessionId);
396
+ (_j = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTED)) === null || _j === void 0 ? void 0 : _j(sessionId);
397
+ (_k = options.onConnected) === null || _k === void 0 ? void 0 : _k.call(options);
316
398
  }
317
399
  }
318
400
  if (events["creds.update"]) {
319
401
  yield saveCreds();
320
402
  }
403
+ // Menangani event update data grup
404
+ if (events["groups.update"]) {
405
+ const updates = events["groups.update"];
406
+ for (const update of updates) {
407
+ try {
408
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
409
+ const metadata = yield sock.groupMetadata(update.id);
410
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
411
+ }
412
+ catch (error) {
413
+ console.error(`Error updating group metadata in cache: ${error}`);
414
+ }
415
+ }
416
+ }
417
+ // Menangani event perubahan peserta grup
418
+ if (events["group-participants.update"]) {
419
+ const update = events["group-participants.update"];
420
+ try {
421
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
422
+ const metadata = yield sock.groupMetadata(update.id);
423
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
424
+ }
425
+ catch (error) {
426
+ console.error(`Error updating group participants in cache: ${error}`);
427
+ }
428
+ }
321
429
  if (events["messages.update"]) {
322
430
  const msg = events["messages.update"][0];
323
431
  const data = Object.assign({ sessionId: sessionId, messageStatus: (0, message_status_1.parseMessageStatusCodeToReadable)(msg.update.status) }, msg);
324
- (_h = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED)) === null || _h === void 0 ? void 0 : _h(sessionId, data);
432
+ (_l = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED)) === null || _l === void 0 ? void 0 : _l(sessionId, data);
433
+ (_m = options.onMessageUpdated) === null || _m === void 0 ? void 0 : _m.call(options, data);
325
434
  }
326
435
  if (events["messages.upsert"]) {
327
- const msg = (_j = events["messages.upsert"]
328
- .messages) === null || _j === void 0 ? void 0 : _j[0];
329
- msg.sessionId = sessionId;
330
- msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
331
- msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
332
- msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
333
- msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
334
- (_k = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _k === void 0 ? void 0 : _k(Object.assign({}, msg));
436
+ const messages = events["messages.upsert"].messages || [];
437
+ for (const rawMsg of messages) {
438
+ // Skip protocol messages and system messages
439
+ if ((_o = rawMsg.message) === null || _o === void 0 ? void 0 : _o.protocolMessage) {
440
+ continue;
441
+ }
442
+ // Skip messages without content
443
+ if (!rawMsg.message || Object.keys(rawMsg.message).length === 0) {
444
+ continue;
445
+ }
446
+ const msg = rawMsg;
447
+ msg.sessionId = sessionId;
448
+ msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
449
+ msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
450
+ msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
451
+ msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
452
+ (_p = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _p === void 0 ? void 0 : _p(Object.assign({}, msg));
453
+ (_q = options.onMessageReceived) === null || _q === void 0 ? void 0 : _q.call(options, msg);
454
+ }
335
455
  }
336
456
  }));
337
457
  return sock;
@@ -348,6 +468,45 @@ exports.startSessionWithPairingCode = startSessionWithPairingCode;
348
468
  * @deprecated Use startSession method instead
349
469
  */
350
470
  exports.startWhatsapp = exports.startSession;
471
+ /**
472
+ * Soft delete session - removes from memory but preserves MongoDB data for pairing code sessions
473
+ * @param sessionId Session ID to soft delete
474
+ */
475
+ const softDeleteSession = (sessionId_1, ...args_1) => __awaiter(void 0, [sessionId_1, ...args_1], void 0, function* (sessionId, preserveData = false) {
476
+ const session = (0, exports.getSession)(sessionId);
477
+ try {
478
+ yield (session === null || session === void 0 ? void 0 : session.logout());
479
+ }
480
+ catch (error) { }
481
+ session === null || session === void 0 ? void 0 : session.end(undefined);
482
+ sessions.delete(sessionId);
483
+ // Only completely remove from MongoDB if not preserving data or not a pairing code session
484
+ if (!preserveData && !pairingCodeSessions.has(sessionId)) {
485
+ if (authCollection) {
486
+ try {
487
+ yield authCollection.deleteOne({ sessionId });
488
+ }
489
+ catch (error) {
490
+ console.error(`Error deleting session ${sessionId} from MongoDB:`, error);
491
+ }
492
+ }
493
+ }
494
+ else if (pairingCodeSessions.has(sessionId)) {
495
+ // Preserving MongoDB data for pairing code session
496
+ }
497
+ // Hapus cache grup untuk session ini
498
+ try {
499
+ yield Utils_1.groupCache.clearSessionCache(sessionId);
500
+ }
501
+ catch (error) {
502
+ console.error(`Error clearing group cache for session ${sessionId}:`, error);
503
+ }
504
+ // Legacy: hapus juga dari file system jika ada
505
+ const dir = path_1.default.resolve(Defaults_1.CREDENTIALS.DIR_NAME, sessionId + Defaults_1.CREDENTIALS.PREFIX);
506
+ if (fs_1.default.existsSync(dir)) {
507
+ fs_1.default.rmSync(dir, { force: true, recursive: true });
508
+ }
509
+ });
351
510
  const deleteSession = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
352
511
  const session = (0, exports.getSession)(sessionId);
353
512
  try {
@@ -356,11 +515,12 @@ const deleteSession = (sessionId) => __awaiter(void 0, void 0, void 0, function*
356
515
  catch (error) { }
357
516
  session === null || session === void 0 ? void 0 : session.end(undefined);
358
517
  sessions.delete(sessionId);
518
+ // Hapus tracking pairing code session jika ada
519
+ pairingCodeSessions.delete(sessionId);
359
520
  // Hapus juga dari MongoDB jika authCollection ada
360
521
  if (authCollection) {
361
522
  try {
362
523
  yield authCollection.deleteOne({ sessionId });
363
- console.log(`Session ${sessionId} deleted from MongoDB`);
364
524
  }
365
525
  catch (error) {
366
526
  console.error(`Error deleting session ${sessionId} from MongoDB:`, error);
@@ -369,7 +529,6 @@ const deleteSession = (sessionId) => __awaiter(void 0, void 0, void 0, function*
369
529
  // Hapus cache grup untuk session ini
370
530
  try {
371
531
  yield Utils_1.groupCache.clearSessionCache(sessionId);
372
- console.log(`Group metadata cache for session ${sessionId} cleared`);
373
532
  }
374
533
  catch (error) {
375
534
  console.error(`Error clearing group cache for session ${sessionId}:`, error);
@@ -479,7 +638,8 @@ const onMessageUpdate = (listener) => {
479
638
  };
480
639
  exports.onMessageUpdate = onMessageUpdate;
481
640
  const onPairingCode = (listener) => {
482
- callback.set(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED, listener);
641
+ // Set callback ke registry dengan key yang benar
642
+ callback.set(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE, listener);
483
643
  };
484
644
  exports.onPairingCode = onPairingCode;
485
645
  /**
@@ -511,7 +671,6 @@ exports.loadSessionsFromMongo = loadSessionsFromMongo;
511
671
  const setMongoDBNames = (dbName = "wa_session", collectionName = "auth") => {
512
672
  Defaults_1.CREDENTIALS.MONGO_DB_NAME = dbName;
513
673
  Defaults_1.CREDENTIALS.MONGO_COLLECTION_NAME = collectionName;
514
- console.log(`MongoDB names configured: database="${dbName}", collection="${collectionName}"`);
515
674
  };
516
675
  exports.setMongoDBNames = setMongoDBNames;
517
676
  /**
@@ -555,36 +714,115 @@ const reconnect = (sessionId) => __awaiter(void 0, void 0, void 0, function* ()
555
714
  }
556
715
  // Tunggu sedikit waktu untuk memastikan cleanup selesai
557
716
  yield (0, create_delay_1.createDelay)(1000);
558
- // Cek jika data session tersedia di MongoDB
559
- yield initMongo();
560
- const sessionExists = yield shouldLoadSession(sessionId);
561
- if (sessionExists) {
562
- // Mulai session baru dari data yang tersimpan di MongoDB
563
- // Gunakan opsi khusus untuk reconnect
717
+ // Cek jika ini session pairing code dari tracking terlebih dahulu
718
+ const pairingInfo = pairingCodeSessions.get(sessionId);
719
+ if (pairingInfo) {
720
+ // Ini adalah session pairing code, gunakan metode pairing code untuk reconnect
564
721
  try {
565
- yield (0, exports.startSession)(sessionId, {
566
- printQR: false,
722
+ // Reset retry count untuk session ini
723
+ retryCount.delete(sessionId);
724
+ yield (0, exports.startSessionWithPairingCode)(sessionId, pairingInfo.phoneNumber, Object.assign(Object.assign({}, pairingInfo.options), { printQR: false,
567
725
  // Tambahkan callback khusus untuk reconnect
568
- onConnected: () => { },
569
- onDisconnected: () => { },
570
- onQRUpdated: (qr) => { }
571
- });
726
+ onConnected: () => {
727
+ // Pairing code session reconnected successfully
728
+ }, onDisconnected: () => {
729
+ // Pairing code session disconnected after reconnect
730
+ } }));
572
731
  // Periksa jika session berhasil dimulai
573
732
  return !!(0, exports.getSession)(sessionId);
574
733
  }
575
734
  catch (startError) {
735
+ console.error(`Failed to reconnect pairing code session ${sessionId}:`, startError.message);
576
736
  return false;
577
737
  }
578
738
  }
579
739
  else {
580
- return false;
740
+ // Cek jika data session tersedia di MongoDB untuk session biasa
741
+ yield initMongo();
742
+ const sessionExists = yield shouldLoadSession(sessionId);
743
+ if (sessionExists) {
744
+ // Session biasa, gunakan metode startSession normal
745
+ try {
746
+ yield (0, exports.startSession)(sessionId, {
747
+ printQR: false,
748
+ // Tambahkan callback khusus untuk reconnect
749
+ onConnected: () => {
750
+ // Session reconnected successfully
751
+ },
752
+ onDisconnected: () => {
753
+ // Session disconnected after reconnect
754
+ },
755
+ onQRUpdated: (qr) => {
756
+ // QR code updated for reconnecting session
757
+ }
758
+ });
759
+ // Periksa jika session berhasil dimulai
760
+ return !!(0, exports.getSession)(sessionId);
761
+ }
762
+ catch (startError) {
763
+ console.error(`Failed to reconnect session ${sessionId}:`, startError.message);
764
+ return false;
765
+ }
766
+ }
767
+ else {
768
+ // No session data found in MongoDB
769
+ return false;
770
+ }
581
771
  }
582
772
  }
583
773
  catch (error) {
774
+ console.error(`Error during reconnect for session ${sessionId}:`, error.message);
584
775
  return false;
585
776
  }
586
777
  });
587
778
  exports.reconnect = reconnect;
779
+ /**
780
+ * Reconnect all pairing code sessions that are tracked
781
+ * Useful for bulk reconnection after system restart
782
+ */
783
+ const reconnectAllPairingCodeSessions = () => __awaiter(void 0, void 0, void 0, function* () {
784
+ const results = {};
785
+ for (const [sessionId, sessionInfo] of pairingCodeSessions.entries()) {
786
+ try {
787
+ const success = yield (0, exports.reconnect)(sessionId);
788
+ results[sessionId] = success;
789
+ // Add delay between reconnection attempts
790
+ yield (0, create_delay_1.createDelay)(2000);
791
+ }
792
+ catch (error) {
793
+ console.error(`Error reconnecting pairing code session ${sessionId}:`, error.message);
794
+ results[sessionId] = false;
795
+ }
796
+ }
797
+ return results;
798
+ });
799
+ exports.reconnectAllPairingCodeSessions = reconnectAllPairingCodeSessions;
800
+ /**
801
+ * Get all tracked pairing code sessions
802
+ * @returns Array of session IDs that were created with pairing code
803
+ */
804
+ const getPairingCodeSessions = () => {
805
+ return Array.from(pairingCodeSessions.keys());
806
+ };
807
+ exports.getPairingCodeSessions = getPairingCodeSessions;
808
+ /**
809
+ * Get session status information
810
+ * @param sessionId Session ID to check
811
+ * @returns Object with session status information
812
+ */
813
+ const getSessionStatus = (sessionId) => {
814
+ const isRunning = !!(0, exports.getSession)(sessionId);
815
+ const isPairingCodeSession = pairingCodeSessions.has(sessionId);
816
+ const retryAttempts = retryCount.get(sessionId) || 0;
817
+ return {
818
+ sessionId,
819
+ isRunning,
820
+ isPairingCodeSession,
821
+ retryAttempts,
822
+ hasCredentials: isRunning ? true : null // null means unknown when not running
823
+ };
824
+ };
825
+ exports.getSessionStatus = getSessionStatus;
588
826
  // Fungsi baru untuk mendapatkan konfigurasi TTL cache grup
589
827
  const setGroupCacheConfig = (options) => {
590
828
  Utils_1.groupCache.setConfig(options);
@@ -54,6 +54,7 @@ export interface StartSessionParams {
54
54
  onConnected?: () => void;
55
55
  onConnecting?: () => void;
56
56
  onDisconnected?: () => void;
57
+ onPairingCode?: (code: string) => void;
57
58
  onMessageReceived?: (message: MessageReceived) => void;
58
59
  onMessageUpdated?: (message: MessageUpdated) => void;
59
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,eAAe;IAC5D;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAG5B,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACvD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,iCAAiC;IAChD;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EACT,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,GACX,MAAM,GACN,QAAQ,CAAC;CACd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,eAAe;IAC5D;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGvC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACvD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,iCAAiC;IAChD;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EACT,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,GACX,MAAM,GACN,QAAQ,CAAC;CACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wa-multi-mongodb",
3
- "version": "3.9.5",
3
+ "version": "3.9.7",
4
4
  "description": "Multi Session Whatsapp Library with MongoDB Integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,7 +19,8 @@
19
19
  "@hapi/boom": "^10.0.1",
20
20
  "@types/node-cache": "^4.1.3",
21
21
  "@types/qrcode": "^1.5.5",
22
- "baileys": "^6.7.18",
22
+ "aws4": "^1.13.2",
23
+ "baileys": "github:WhiskeySockets/Baileys#next",
23
24
  "dotenv": "^16.5.0",
24
25
  "link-preview-js": "^3.0.14",
25
26
  "mime": "^3.0.0",
package/readme.md CHANGED
@@ -98,7 +98,7 @@ For secure MongoDB URI management, we recommend using environment variables:
98
98
  ### Session Management
99
99
 
100
100
  ```javascript
101
- // Start a new session
101
+ // Start a new session with QR Code
102
102
  const session = await whatsapp.startSession("mysession");
103
103
 
104
104
  // Start with options
@@ -106,7 +106,22 @@ await whatsapp.startSession("mysession2", {
106
106
  printQR: true,
107
107
  onConnected: () => console.log("Connected!"),
108
108
  onDisconnected: () => console.log("Disconnected!"),
109
- onQRUpdated: (qr) => console.log("New QR:", qr)
109
+ onQRUpdated: (qr) => {
110
+ console.log("New QR:", qr);
111
+ // QR data is raw and ready for frontend use
112
+ // You can display this in React, Vue, Angular, etc.
113
+ }
114
+ });
115
+
116
+ // Start session with Pairing Code (v3.9.6+)
117
+ await whatsapp.startSessionWithPairingCode("mysession3", {
118
+ mobile: "6281234567890", // your phone number with country code
119
+ onConnected: () => console.log("Pairing session connected!"),
120
+ onDisconnected: () => console.log("Pairing session disconnected!"),
121
+ onPairingCode: (code) => {
122
+ console.log("Pairing code:", code);
123
+ // Enter this code in your WhatsApp app: Settings > Linked Devices > Link a Device > Link with phone number
124
+ }
110
125
  });
111
126
 
112
127
  // Get all active sessions
@@ -117,6 +132,27 @@ const sessionData = whatsapp.getSession("mysession");
117
132
 
118
133
  // Load all saved sessions from MongoDB
119
134
  await whatsapp.loadSessionsFromMongo();
135
+
136
+ // Session Management Utilities (v3.9.6+)
137
+ // Get session status with detailed information
138
+ const status = await whatsapp.getSessionStatus("mysession");
139
+ console.log("Session status:", status);
140
+ // Returns: { exists: true, connected: true, sessionType: 'qr' | 'pairing' }
141
+
142
+ // Manual reconnection for any session
143
+ try {
144
+ const reconnected = await whatsapp.reconnect("mysession");
145
+ console.log("Reconnection successful:", reconnected);
146
+ } catch (error) {
147
+ console.error("Reconnection failed:", error);
148
+ }
149
+
150
+ // Get all pairing code sessions
151
+ const pairingSessions = whatsapp.getPairingCodeSessions();
152
+ console.log("Pairing code sessions:", pairingSessions);
153
+
154
+ // Bulk reconnect all pairing code sessions
155
+ await whatsapp.reconnectAllPairingCodeSessions();
120
156
  ```
121
157
 
122
158
  ### Sending Messages
@@ -511,6 +547,214 @@ startApp().catch(err => {
511
547
  });
512
548
  ```
513
549
 
550
+ ## Complete Example: Pairing Code with Auto-Reconnect (v3.9.6+)
551
+
552
+ ```javascript
553
+ import * as whatsapp from "wa-multi-mongodb";
554
+ require('dotenv').config();
555
+
556
+ // Store connection status
557
+ const sessionStatus = {};
558
+
559
+ async function startPairingApp() {
560
+ // MongoDB Configuration
561
+ await whatsapp.setMongoURI(process.env.MONGODB_URI);
562
+
563
+ // Event listeners for pairing code sessions
564
+ whatsapp.onConnected((sessionId) => {
565
+ console.log(`Pairing session ${sessionId} connected!`);
566
+ sessionStatus[sessionId] = 'connected';
567
+ });
568
+
569
+ whatsapp.onDisconnected(async (sessionId) => {
570
+ console.log(`Pairing session ${sessionId} disconnected!`);
571
+ sessionStatus[sessionId] = 'disconnected';
572
+
573
+ // Check if it's a pairing code session
574
+ const status = await whatsapp.getSessionStatus(sessionId);
575
+ if (status.sessionType === 'pairing') {
576
+ console.log(`Attempting to reconnect pairing session ${sessionId}...`);
577
+
578
+ // Auto-reconnect after 5 seconds
579
+ setTimeout(async () => {
580
+ try {
581
+ const reconnected = await whatsapp.reconnect(sessionId);
582
+ if (reconnected) {
583
+ console.log(`Pairing session ${sessionId} reconnected successfully!`);
584
+ sessionStatus[sessionId] = 'connected';
585
+ }
586
+ } catch (error) {
587
+ console.error(`Failed to reconnect pairing session ${sessionId}:`, error);
588
+ }
589
+ }, 5000);
590
+ }
591
+ });
592
+
593
+ // Message handler
594
+ whatsapp.onMessageReceived(async (msg) => {
595
+ if (msg.key.fromMe || msg.key.remoteJid.includes("status")) return;
596
+
597
+ const messageContent = msg.message?.conversation ||
598
+ msg.message?.extendedTextMessage?.text ||
599
+ "";
600
+
601
+ console.log(`Message from ${msg.key.remoteJid}: ${messageContent}`);
602
+
603
+ // Auto-reply example
604
+ if (messageContent.toLowerCase().includes("ping")) {
605
+ await whatsapp.sendTextMessage({
606
+ sessionId: msg.sessionId,
607
+ to: msg.key.remoteJid,
608
+ text: "Pong! Message received from pairing session.",
609
+ answering: msg
610
+ });
611
+ }
612
+ });
613
+
614
+ // Load existing sessions from MongoDB
615
+ await whatsapp.loadSessionsFromMongo();
616
+
617
+ // Start a new pairing code session
618
+ const pairingSessionId = "pairing_session_1";
619
+ const yourPhoneNumber = "6281234567890"; // Replace with your phone number
620
+
621
+ try {
622
+ await whatsapp.startSessionWithPairingCode(pairingSessionId, {
623
+ mobile: yourPhoneNumber,
624
+ onConnected: () => {
625
+ console.log("Pairing session connected successfully!");
626
+ sessionStatus[pairingSessionId] = 'connected';
627
+ },
628
+ onDisconnected: () => {
629
+ console.log("Pairing session disconnected!");
630
+ sessionStatus[pairingSessionId] = 'disconnected';
631
+ },
632
+ onPairingCode: (code) => {
633
+ console.log("\n" + "=".repeat(50));
634
+ console.log("📱 PAIRING CODE:", code);
635
+ console.log("=".repeat(50));
636
+ console.log("1. Open WhatsApp on your phone");
637
+ console.log("2. Go to Settings > Linked Devices");
638
+ console.log("3. Tap 'Link a Device'");
639
+ console.log("4. Tap 'Link with phone number instead'");
640
+ console.log("5. Enter the pairing code above");
641
+ console.log("=".repeat(50) + "\n");
642
+ }
643
+ });
644
+
645
+ sessionStatus[pairingSessionId] = 'connecting';
646
+ } catch (error) {
647
+ console.error("Error starting pairing session:", error);
648
+ }
649
+
650
+ // Periodic health check for pairing sessions
651
+ setInterval(async () => {
652
+ const pairingSessions = whatsapp.getPairingCodeSessions();
653
+ console.log(`Active pairing sessions: ${pairingSessions.length}`);
654
+
655
+ // Check each pairing session status
656
+ for (const sessionId of pairingSessions) {
657
+ const status = await whatsapp.getSessionStatus(sessionId);
658
+ console.log(`Session ${sessionId}: ${status.connected ? 'Connected' : 'Disconnected'}`);
659
+
660
+ if (!status.connected && sessionStatus[sessionId] === 'connected') {
661
+ console.log(`Detected disconnection for ${sessionId}, attempting reconnect...`);
662
+ try {
663
+ await whatsapp.reconnect(sessionId);
664
+ } catch (error) {
665
+ console.error(`Reconnect failed for ${sessionId}:`, error);
666
+ }
667
+ }
668
+ }
669
+ }, 30000); // Check every 30 seconds
670
+
671
+ // Bulk reconnect utility
672
+ setInterval(async () => {
673
+ try {
674
+ await whatsapp.reconnectAllPairingCodeSessions();
675
+ console.log("Bulk reconnect completed for all pairing sessions");
676
+ } catch (error) {
677
+ console.error("Bulk reconnect failed:", error);
678
+ }
679
+ }, 10 * 60 * 1000); // Every 10 minutes
680
+
681
+ console.log("Pairing code application started!");
682
+ }
683
+
684
+ startPairingApp().catch(err => {
685
+ console.error("Failed to start pairing application:", err);
686
+ process.exit(1);
687
+ });
688
+ ```
689
+
690
+ ## Frontend Integration Example: QR Code Display (v3.9.6+)
691
+
692
+ ```javascript
693
+ // React.js example for QR code display
694
+ import React, { useState, useEffect } from 'react';
695
+ import QRCode from 'qrcode';
696
+ import * as whatsapp from "wa-multi-mongodb";
697
+
698
+ function WhatsAppQRComponent() {
699
+ const [qrDataURL, setQrDataURL] = useState('');
700
+ const [sessionStatus, setSessionStatus] = useState('disconnected');
701
+
702
+ useEffect(() => {
703
+ // Initialize WhatsApp connection
704
+ const initWhatsApp = async () => {
705
+ await whatsapp.setMongoURI(process.env.REACT_APP_MONGODB_URI);
706
+
707
+ // Start session with simplified QR callback
708
+ await whatsapp.startSession("frontend_session", {
709
+ printQR: false, // Don't print in terminal
710
+ onQRUpdated: async (qr) => {
711
+ // QR data is raw and ready for frontend use
712
+ try {
713
+ const qrDataURL = await QRCode.toDataURL(qr);
714
+ setQrDataURL(qrDataURL);
715
+ } catch (error) {
716
+ console.error('Error generating QR code:', error);
717
+ }
718
+ },
719
+ onConnected: () => {
720
+ setSessionStatus('connected');
721
+ setQrDataURL(''); // Clear QR when connected
722
+ },
723
+ onDisconnected: () => {
724
+ setSessionStatus('disconnected');
725
+ }
726
+ });
727
+ };
728
+
729
+ initWhatsApp().catch(console.error);
730
+ }, []);
731
+
732
+ return (
733
+ <div className="whatsapp-qr">
734
+ <h2>WhatsApp Connection</h2>
735
+ <div className="status">
736
+ Status: <span className={sessionStatus}>{sessionStatus}</span>
737
+ </div>
738
+
739
+ {qrDataURL && (
740
+ <div className="qr-container">
741
+ <p>Scan this QR code with WhatsApp:</p>
742
+ <img src={qrDataURL} alt="WhatsApp QR Code" />
743
+ </div>
744
+ )}
745
+
746
+ {sessionStatus === 'connected' && (
747
+ <div className="connected">
748
+ <p>✅ WhatsApp connected successfully!</p>
749
+ </div>
750
+ )}
751
+ </div>
752
+ );
753
+ }
754
+
755
+ export default WhatsAppQRComponent;
756
+ ```
757
+
514
758
  ## Best Practices for Group Chats
515
759
 
516
760
  1. **Auto Group Detection**: Since v3.9.0, the library automatically detects if a chat is a group based on its JID format
@@ -529,7 +773,37 @@ startApp().catch(err => {
529
773
 
530
774
  ## Changelog
531
775
 
532
- ### v3.9.5 (current)
776
+ ### v3.9.7 (latest)
777
+ - **Enhanced Message Processing for Group Chats**: Fixed issues with group message handling and improved message processing architecture
778
+ - **Multiple Message Processing**: Event handler `messages.upsert` now processes all messages in array instead of only the first message
779
+ - **Improved Message Filtering**: Added intelligent filtering to skip protocol messages and empty messages while preserving valid group messages
780
+ - **Enhanced Group Message Support**: Better detection and processing of group messages with participant information
781
+ - **Group vs Private Chat Detection**: Better differentiation between group and private messages
782
+ - **Improved Error Recovery**: Better error handling without changing existing error patterns
783
+
784
+ ### v3.9.6
785
+ - **Enhanced Pairing Code Support**: Added comprehensive pairing code session management with auto-reconnect capabilities
786
+ - New `startSessionWithPairingCode()` function for creating sessions using pairing codes
787
+ - Intelligent session tracking system that preserves pairing code session data across disconnections
788
+ - Enhanced auto-reconnect mechanism that differentiates between QR code and pairing code sessions
789
+ - Session persistence in MongoDB for pairing code sessions to enable seamless reconnection
790
+ - **New Utility Functions for Session Management**:
791
+ - `reconnect(sessionId)` - Manual reconnection for any session type
792
+ - `reconnectAllPairingCodeSessions()` - Bulk reconnection for all tracked pairing code sessions
793
+ - `getPairingCodeSessions()` - Get list of all pairing code session IDs
794
+ - `getSessionStatus(sessionId)` - Get detailed session status information including session type
795
+ - **QR Data Raw for Frontend Integration**: Simplified QR handling optimized for frontend development
796
+ - Cleaned up QR callback to provide only essential QR data raw for frontend processing
797
+ - Removed unnecessary QR string complexity from callbacks for better performance
798
+ - QR data can be directly used with any frontend QR code library (React, Vue, Angular, etc.)
799
+ - Terminal QR display handled automatically via `printQR` option
800
+ - **Breaking Changes**:
801
+ - Simplified `onQRUpdated` callback signature: removed `qrString` parameter, now only provides raw QR data
802
+ - Session-level `onQRUpdated` option simplified from `(qr, qrString)` to `(qr)` only
803
+ - **Enhanced Session Persistence**: Pairing code sessions maintain authentication state in MongoDB during disconnections
804
+ - **Improved Error Handling**: Better error recovery and automatic session restoration for pairing code sessions
805
+
806
+ ### v3.9.5
533
807
  - New `deleteMessage()` function for deleting messages
534
808
  - Support for deleting both own messages and others' messages (requires admin permissions in groups)
535
809
  - Auto-delete message utility function example
@@ -592,4 +866,4 @@ startApp().catch(err => {
592
866
 
593
867
  ## License
594
868
 
595
- ISC
869
+ ISC