wa-multi-mongodb 3.10.2 → 3.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/Defaults/index.js +4 -9
  2. package/dist/Error/index.js +1 -5
  3. package/dist/Messaging/index.d.ts +1 -1
  4. package/dist/Messaging/index.js +123 -137
  5. package/dist/Profile/index.d.ts +1 -1
  6. package/dist/Profile/index.js +6 -10
  7. package/dist/Socket/index.d.ts +160 -1
  8. package/dist/Socket/index.d.ts.map +1 -1
  9. package/dist/Socket/index.js +462 -200
  10. package/dist/Types/index.d.ts +21 -0
  11. package/dist/Types/index.d.ts.map +1 -1
  12. package/dist/Types/index.js +1 -2
  13. package/dist/Types/profile.js +1 -2
  14. package/dist/Utils/create-delay.js +2 -7
  15. package/dist/Utils/error.js +1 -4
  16. package/dist/Utils/group-cache.js +8 -15
  17. package/dist/Utils/index.d.ts +5 -5
  18. package/dist/Utils/index.js +5 -21
  19. package/dist/Utils/is-exist.d.ts +1 -1
  20. package/dist/Utils/is-exist.js +7 -10
  21. package/dist/Utils/lid-utils.js +13 -20
  22. package/dist/Utils/message-status.d.ts +1 -1
  23. package/dist/Utils/message-status.js +7 -11
  24. package/dist/Utils/mongo-auth-state.js +10 -13
  25. package/dist/Utils/phone-to-jid.js +6 -14
  26. package/dist/Utils/save-media.d.ts +1 -1
  27. package/dist/Utils/save-media.js +16 -26
  28. package/dist/cjs/Defaults/index.d.ts +21 -0
  29. package/dist/cjs/Defaults/index.d.ts.map +1 -0
  30. package/dist/cjs/Defaults/index.js +31 -0
  31. package/dist/cjs/Error/index.d.ts +5 -0
  32. package/dist/cjs/Error/index.d.ts.map +1 -0
  33. package/dist/cjs/Error/index.js +14 -0
  34. package/dist/cjs/Messaging/index.d.ts +45 -0
  35. package/dist/cjs/Messaging/index.d.ts.map +1 -0
  36. package/dist/cjs/Messaging/index.js +784 -0
  37. package/dist/cjs/Profile/index.d.ts +9 -0
  38. package/dist/cjs/Profile/index.d.ts.map +1 -0
  39. package/dist/cjs/Profile/index.js +34 -0
  40. package/dist/cjs/Socket/index.d.ts +264 -0
  41. package/dist/cjs/Socket/index.d.ts.map +1 -0
  42. package/dist/cjs/Socket/index.js +1210 -0
  43. package/dist/cjs/Types/index.d.ts +95 -0
  44. package/dist/cjs/Types/index.d.ts.map +1 -0
  45. package/dist/cjs/Types/index.js +2 -0
  46. package/dist/cjs/Types/profile.d.ts +5 -0
  47. package/dist/cjs/Types/profile.d.ts.map +1 -0
  48. package/dist/cjs/Types/profile.js +2 -0
  49. package/dist/cjs/Utils/create-delay.d.ts +17 -0
  50. package/dist/cjs/Utils/create-delay.d.ts.map +1 -0
  51. package/dist/cjs/Utils/create-delay.js +38 -0
  52. package/dist/cjs/Utils/error.d.ts +4 -0
  53. package/dist/cjs/Utils/error.d.ts.map +1 -0
  54. package/dist/cjs/Utils/error.js +8 -0
  55. package/dist/cjs/Utils/group-cache.d.ts +23 -0
  56. package/dist/cjs/Utils/group-cache.d.ts.map +1 -0
  57. package/dist/cjs/Utils/group-cache.js +176 -0
  58. package/dist/cjs/Utils/index.d.ts +6 -0
  59. package/dist/cjs/Utils/index.d.ts.map +1 -0
  60. package/dist/cjs/Utils/index.js +23 -0
  61. package/dist/cjs/Utils/is-exist.d.ts +6 -0
  62. package/dist/cjs/Utils/is-exist.d.ts.map +1 -0
  63. package/dist/cjs/Utils/is-exist.js +53 -0
  64. package/dist/cjs/Utils/lid-utils.d.ts +26 -0
  65. package/dist/cjs/Utils/lid-utils.d.ts.map +1 -0
  66. package/dist/cjs/Utils/lid-utils.js +81 -0
  67. package/dist/cjs/Utils/message-status.d.ts +4 -0
  68. package/dist/cjs/Utils/message-status.d.ts.map +1 -0
  69. package/dist/cjs/Utils/message-status.js +18 -0
  70. package/dist/cjs/Utils/mongo-auth-state.d.ts +15 -0
  71. package/dist/cjs/Utils/mongo-auth-state.d.ts.map +1 -0
  72. package/dist/cjs/Utils/mongo-auth-state.js +109 -0
  73. package/dist/cjs/Utils/phone-to-jid.d.ts +17 -0
  74. package/dist/cjs/Utils/phone-to-jid.d.ts.map +1 -0
  75. package/dist/cjs/Utils/phone-to-jid.js +51 -0
  76. package/dist/cjs/Utils/save-media.d.ts +6 -0
  77. package/dist/cjs/Utils/save-media.d.ts.map +1 -0
  78. package/dist/cjs/Utils/save-media.js +55 -0
  79. package/dist/cjs/index.d.ts +8 -0
  80. package/dist/cjs/index.d.ts.map +1 -0
  81. package/dist/cjs/index.js +46 -0
  82. package/dist/index.d.ts +6 -6
  83. package/dist/index.js +7 -46
  84. package/package.json +57 -42
  85. package/readme.md +170 -3
@@ -0,0 +1,1210 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.toLID = exports.toPhoneNumber = exports.isPNFormat = exports.isLIDFormat = exports.getAllLIDMappings = exports.getLIDForPN = exports.getPNForLID = 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
+ exports.setMongoCollection = setMongoCollection;
50
+ const baileys_1 = __importStar(require("baileys"));
51
+ const path_1 = __importDefault(require("path"));
52
+ const fs_1 = __importDefault(require("fs"));
53
+ const qrcode_1 = __importDefault(require("qrcode"));
54
+ const pino_1 = __importDefault(require("pino"));
55
+ const Defaults_1 = require("../Defaults");
56
+ const save_media_1 = require("../Utils/save-media");
57
+ const Utils_1 = require("../Utils");
58
+ const Error_1 = require("../Error");
59
+ const message_status_1 = require("../Utils/message-status");
60
+ const mongodb_1 = require("mongodb");
61
+ const mongo_auth_state_1 = require("../Utils/mongo-auth-state");
62
+ const create_delay_1 = require("../Utils/create-delay");
63
+ const sessions = new Map();
64
+ /**
65
+ * Helper function to generate browser configuration based on type and name
66
+ * @param browserType - Browser type (ubuntu, macOS, windows, appropriate)
67
+ * @param browserName - Custom browser/app name
68
+ * @returns Browser configuration tuple for Baileys
69
+ */
70
+ const getBrowserConfig = (browserType = "ubuntu", browserName = "Chrome") => {
71
+ let browserTuple;
72
+ switch (browserType) {
73
+ case "macOS":
74
+ browserTuple = baileys_1.Browsers.macOS(browserName);
75
+ break;
76
+ case "windows":
77
+ browserTuple = baileys_1.Browsers.windows(browserName);
78
+ break;
79
+ case "appropriate":
80
+ browserTuple = baileys_1.Browsers.appropriate(browserName);
81
+ break;
82
+ case "ubuntu":
83
+ default:
84
+ browserTuple = baileys_1.Browsers.ubuntu(browserName);
85
+ break;
86
+ }
87
+ // Convert readonly tuple to mutable tuple for Baileys compatibility
88
+ return [...browserTuple];
89
+ };
90
+ const callback = new Map();
91
+ const retryCount = new Map();
92
+ // Tambahkan Map untuk melacak session yang menggunakan pairing code
93
+ const pairingCodeSessions = new Map();
94
+ const P = (0, pino_1.default)({
95
+ level: "silent",
96
+ });
97
+ // Tambahkan variabel global untuk koneksi MongoDB dan collection
98
+ let mongoClient;
99
+ let authCollection = null;
100
+ let mongoURI = process.env.MONGODB_URI || "mongodb://localhost:27017";
101
+ /**
102
+ * Set MongoDB URI for connection
103
+ * This function will be used to configure MongoDB connection with just the URI
104
+ *
105
+ * @param uri MongoDB connection URI
106
+ */
107
+ const setMongoURI = (uri) => __awaiter(void 0, void 0, void 0, function* () {
108
+ mongoURI = uri;
109
+ // Configure group cache MongoDB connection as well
110
+ yield Utils_1.groupCache.setMongoURI(uri);
111
+ // Reset MongoDB client and collection to ensure they are recreated with new URI
112
+ if (mongoClient) {
113
+ try {
114
+ yield mongoClient.close();
115
+ }
116
+ catch (error) {
117
+ console.error("Error closing existing MongoDB connection:", error);
118
+ }
119
+ mongoClient = undefined;
120
+ authCollection = null;
121
+ }
122
+ // MongoDB URI configured successfully - removed console.log for npm package
123
+ });
124
+ exports.setMongoURI = setMongoURI;
125
+ function setMongoCollection(collection) {
126
+ authCollection = collection;
127
+ }
128
+ function initMongo() {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ if (!authCollection) {
131
+ if (!mongoClient) {
132
+ mongoClient = new mongodb_1.MongoClient(mongoURI);
133
+ yield mongoClient.connect();
134
+ }
135
+ // Gunakan variabel dari CREDENTIALS
136
+ const dbName = Defaults_1.CREDENTIALS.MONGO_DB_NAME;
137
+ const collectionName = Defaults_1.CREDENTIALS.MONGO_COLLECTION_NAME;
138
+ authCollection = mongoClient.db(dbName).collection(collectionName);
139
+ // console.log(`MongoDB initialized with database "${dbName}" and collection "${collectionName}"`);
140
+ }
141
+ });
142
+ }
143
+ const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (sessionId = "mysession", options = { printQR: true }) {
144
+ if (isSessionExistAndRunning(sessionId))
145
+ throw new Error_1.WhatsappError(Defaults_1.Messages.sessionAlreadyExist(sessionId));
146
+ yield initMongo();
147
+ const { version } = yield (0, baileys_1.fetchLatestBaileysVersion)();
148
+ const startSocket = () => __awaiter(void 0, void 0, void 0, function* () {
149
+ const { state, saveCreds } = yield (0, mongo_auth_state_1.useMongoAuthState)(sessionId, authCollection);
150
+ const sock = (0, baileys_1.default)({
151
+ version,
152
+ auth: state,
153
+ logger: P,
154
+ markOnlineOnConnect: false,
155
+ browser: getBrowserConfig(options.browserType, options.browserName),
156
+ // Configure caching group metadata using our hybrid implementation with session ID
157
+ cachedGroupMetadata: (jid) => __awaiter(void 0, void 0, void 0, function* () {
158
+ return yield Utils_1.groupCache.get(sessionId, jid);
159
+ })
160
+ });
161
+ sessions.set(sessionId, Object.assign({}, sock));
162
+ try {
163
+ sock.ev.process((events) => __awaiter(void 0, void 0, void 0, function* () {
164
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
165
+ if (events["connection.update"]) {
166
+ const update = events["connection.update"];
167
+ const { connection, lastDisconnect } = update;
168
+ if (update.qr) {
169
+ // Print QR to console if requested
170
+ if (options.printQR) {
171
+ qrcode_1.default.toString(update.qr, {
172
+ type: 'terminal',
173
+ small: true,
174
+ margin: 1
175
+ }, (err, qrString) => {
176
+ if (!err) {
177
+ console.log(qrString);
178
+ }
179
+ });
180
+ }
181
+ // Send QR data raw to callback for frontend processing
182
+ (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_QR)) === null || _a === void 0 ? void 0 : _a({
183
+ sessionId,
184
+ qr: update.qr
185
+ });
186
+ (_b = options.onQRUpdated) === null || _b === void 0 ? void 0 : _b.call(options, update.qr);
187
+ }
188
+ if (connection == "connecting") {
189
+ (_c = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTING)) === null || _c === void 0 ? void 0 : _c(sessionId);
190
+ (_d = options.onConnecting) === null || _d === void 0 ? void 0 : _d.call(options);
191
+ }
192
+ if (connection === "close") {
193
+ const code = (_f = (_e = lastDisconnect === null || lastDisconnect === void 0 ? void 0 : lastDisconnect.error) === null || _e === void 0 ? void 0 : _e.output) === null || _f === void 0 ? void 0 : _f.statusCode;
194
+ let retryAttempt = (_g = retryCount.get(sessionId)) !== null && _g !== void 0 ? _g : 0;
195
+ let shouldRetry;
196
+ if (code != baileys_1.DisconnectReason.loggedOut && retryAttempt < 10) {
197
+ shouldRetry = true;
198
+ }
199
+ if (shouldRetry) {
200
+ retryAttempt++;
201
+ retryCount.set(sessionId, retryAttempt);
202
+ startSocket();
203
+ }
204
+ else {
205
+ retryCount.delete(sessionId);
206
+ // For pairing code sessions, preserve data for future reconnection
207
+ if (pairingCodeSessions.has(sessionId)) {
208
+ yield softDeleteSession(sessionId, true);
209
+ }
210
+ else {
211
+ // For regular sessions, completely delete
212
+ yield softDeleteSession(sessionId, false);
213
+ }
214
+ (_h = callback.get(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED)) === null || _h === void 0 ? void 0 : _h(sessionId);
215
+ (_j = options.onDisconnected) === null || _j === void 0 ? void 0 : _j.call(options);
216
+ }
217
+ }
218
+ if (connection == "open") {
219
+ retryCount.delete(sessionId);
220
+ (_k = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTED)) === null || _k === void 0 ? void 0 : _k(sessionId);
221
+ (_l = options.onConnected) === null || _l === void 0 ? void 0 : _l.call(options);
222
+ }
223
+ }
224
+ if (events["creds.update"]) {
225
+ yield saveCreds();
226
+ }
227
+ // Menangani event update data grup
228
+ if (events["groups.update"]) {
229
+ const updates = events["groups.update"];
230
+ for (const update of updates) {
231
+ try {
232
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
233
+ const metadata = yield sock.groupMetadata(update.id);
234
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
235
+ }
236
+ catch (error) {
237
+ console.error(`Error updating group metadata in cache: ${error}`);
238
+ }
239
+ }
240
+ }
241
+ // Menangani event perubahan peserta grup
242
+ if (events["group-participants.update"]) {
243
+ const update = events["group-participants.update"];
244
+ try {
245
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
246
+ const metadata = yield sock.groupMetadata(update.id);
247
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
248
+ }
249
+ catch (error) {
250
+ console.error(`Error updating group participants in cache: ${error}`);
251
+ }
252
+ }
253
+ if (events["messages.update"]) {
254
+ const msg = events["messages.update"][0];
255
+ const data = Object.assign({ sessionId: sessionId, messageStatus: (0, message_status_1.parseMessageStatusCodeToReadable)(msg.update.status) }, msg);
256
+ (_m = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED)) === null || _m === void 0 ? void 0 : _m(sessionId, data);
257
+ (_o = options.onMessageUpdated) === null || _o === void 0 ? void 0 : _o.call(options, data);
258
+ }
259
+ if (events["messages.upsert"]) {
260
+ const messages = events["messages.upsert"].messages || [];
261
+ for (const rawMsg of messages) {
262
+ // Skip protocol messages and system messages
263
+ if ((_p = rawMsg.message) === null || _p === void 0 ? void 0 : _p.protocolMessage) {
264
+ continue;
265
+ }
266
+ // Skip messages without content
267
+ if (!rawMsg.message || Object.keys(rawMsg.message).length === 0) {
268
+ continue;
269
+ }
270
+ const msg = rawMsg;
271
+ msg.sessionId = sessionId;
272
+ msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
273
+ msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
274
+ msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
275
+ msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
276
+ (_q = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _q === void 0 ? void 0 : _q(Object.assign({}, msg));
277
+ (_r = options.onMessageReceived) === null || _r === void 0 ? void 0 : _r.call(options, msg);
278
+ }
279
+ }
280
+ }));
281
+ return sock;
282
+ }
283
+ catch (error) {
284
+ // console.log("SOCKET ERROR", error);
285
+ return sock;
286
+ }
287
+ });
288
+ return startSocket();
289
+ });
290
+ exports.startSession = startSession;
291
+ /**
292
+ * Start WhatsApp session using pairing code method
293
+ * This is the recommended way to create sessions with pairing code
294
+ *
295
+ * @param sessionId Unique session identifier
296
+ * @param phoneNumber Phone number with country code (without + prefix)
297
+ * @param options Optional configuration for the session
298
+ * @returns Promise<WASocket> The WhatsApp socket instance
299
+ */
300
+ const startSessionWithPairingCode = (sessionId_1, phoneNumber_1, ...args_1) => __awaiter(void 0, [sessionId_1, phoneNumber_1, ...args_1], void 0, function* (sessionId, phoneNumber, options = {}) {
301
+ if (isSessionExistAndRunning(sessionId))
302
+ throw new Error_1.WhatsappError(Defaults_1.Messages.sessionAlreadyExist(sessionId));
303
+ // Simpan informasi session pairing code untuk auto-reconnect
304
+ pairingCodeSessions.set(sessionId, { phoneNumber, options });
305
+ yield initMongo();
306
+ const { version } = yield (0, baileys_1.fetchLatestBaileysVersion)();
307
+ const startSocket = () => __awaiter(void 0, void 0, void 0, function* () {
308
+ var _a, _b;
309
+ const { state, saveCreds } = yield (0, mongo_auth_state_1.useMongoAuthState)(sessionId, authCollection);
310
+ const sock = (0, baileys_1.default)({
311
+ version,
312
+ auth: state,
313
+ logger: P,
314
+ markOnlineOnConnect: false,
315
+ browser: getBrowserConfig(options.browserType, options.browserName),
316
+ // Opsi tambahan untuk meningkatkan kompatibilitas
317
+ linkPreviewImageThumbnailWidth: 300,
318
+ generateHighQualityLinkPreview: true,
319
+ syncFullHistory: false, // Sinkronisasi hanya riwayat baru
320
+ connectTimeoutMs: 60000, // Timeout koneksi ditingkatkan
321
+ printQRInTerminal: false, // QR tidak dicetak untuk pairing code
322
+ // Configure caching group metadata using our hybrid implementation with session ID
323
+ cachedGroupMetadata: (jid) => __awaiter(void 0, void 0, void 0, function* () {
324
+ return yield Utils_1.groupCache.get(sessionId, jid);
325
+ })
326
+ });
327
+ sessions.set(sessionId, Object.assign({}, sock));
328
+ try {
329
+ if (!sock.authState.creds.registered) {
330
+ // Pastikan kita mendapatkan kode pairing dan menampilkannya dengan jelas
331
+ try {
332
+ // Tambahkan delay untuk memastikan state sudah siap
333
+ yield new Promise(resolve => setTimeout(resolve, 2000));
334
+ // Hapus awalan + dari nomor telepon jika ada
335
+ const phoneNumberFormatted = phoneNumber.replace(/^\+/, '');
336
+ // Memanggil fungsi requestPairingCode dengan nomor telepon yang sudah dibersihkan
337
+ const code = yield sock.requestPairingCode(phoneNumberFormatted);
338
+ // Pastikan kode ada dan merupakan string
339
+ if (code && typeof code === 'string') {
340
+ console.log(`Pairing code untuk session ${sessionId}: ${code}`);
341
+ // Panggil callback yang terdaftar
342
+ (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE)) === null || _a === void 0 ? void 0 : _a(sessionId, code);
343
+ (_b = options.onPairingCode) === null || _b === void 0 ? void 0 : _b.call(options, code);
344
+ }
345
+ else {
346
+ console.error("Error: Kode pairing tidak valid atau kosong");
347
+ }
348
+ }
349
+ catch (error) {
350
+ console.error("Error saat meminta kode pairing:", error);
351
+ throw new Error_1.WhatsappError(`Gagal mendapatkan kode pairing: ${error.message || String(error)}`);
352
+ }
353
+ }
354
+ sock.ev.process((events) => __awaiter(void 0, void 0, void 0, function* () {
355
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
356
+ if (events["connection.update"]) {
357
+ const update = events["connection.update"];
358
+ const { connection, lastDisconnect } = update;
359
+ if (update.qr) {
360
+ // Send QR data raw to callback for frontend processing
361
+ (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_QR)) === null || _a === void 0 ? void 0 : _a({
362
+ sessionId,
363
+ qr: update.qr
364
+ });
365
+ }
366
+ if (connection == "connecting") {
367
+ (_b = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTING)) === null || _b === void 0 ? void 0 : _b(sessionId);
368
+ (_c = options.onConnecting) === null || _c === void 0 ? void 0 : _c.call(options);
369
+ }
370
+ if (connection === "close") {
371
+ 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;
372
+ let retryAttempt = (_f = retryCount.get(sessionId)) !== null && _f !== void 0 ? _f : 0;
373
+ let shouldRetry;
374
+ if (code != baileys_1.DisconnectReason.loggedOut && retryAttempt < 10) {
375
+ shouldRetry = true;
376
+ }
377
+ if (shouldRetry) {
378
+ retryAttempt++;
379
+ retryCount.set(sessionId, retryAttempt);
380
+ // Untuk session pairing code, coba reconnect dengan metode yang tepat
381
+ try {
382
+ // Tunggu sebentar sebelum reconnect
383
+ yield (0, create_delay_1.createDelay)(2000);
384
+ startSocket();
385
+ }
386
+ catch (reconnectError) {
387
+ console.error(`Auto-reconnect failed for session ${sessionId}:`, reconnectError.message);
388
+ // Jika reconnect gagal beberapa kali, coba dengan pairing code lagi (jika masih dalam 3 attempt pertama)
389
+ if (retryAttempt <= 3 && pairingCodeSessions.has(sessionId)) {
390
+ const sessionInfo = pairingCodeSessions.get(sessionId);
391
+ // Bersihkan session lama
392
+ sessions.delete(sessionId);
393
+ // Coba mulai ulang dengan pairing code baru
394
+ setTimeout(() => {
395
+ startSocket().catch(err => {
396
+ console.error(`Failed to restart with pairing code for session ${sessionId}:`, err);
397
+ });
398
+ }, 3000);
399
+ }
400
+ else {
401
+ // Jika sudah terlalu banyak gagal, panggil startSocket biasa
402
+ startSocket();
403
+ }
404
+ }
405
+ }
406
+ else {
407
+ retryCount.delete(sessionId);
408
+ // For pairing code sessions, preserve data for future reconnection
409
+ if (pairingCodeSessions.has(sessionId)) {
410
+ yield softDeleteSession(sessionId, true);
411
+ // Don't remove from pairing code tracking completely to allow manual reconnection
412
+ }
413
+ else {
414
+ pairingCodeSessions.delete(sessionId); // Only delete from tracking if it's not a pairing code session
415
+ yield softDeleteSession(sessionId, false);
416
+ }
417
+ (_g = callback.get(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED)) === null || _g === void 0 ? void 0 : _g(sessionId);
418
+ (_h = options.onDisconnected) === null || _h === void 0 ? void 0 : _h.call(options);
419
+ }
420
+ }
421
+ if (connection == "open") {
422
+ retryCount.delete(sessionId);
423
+ (_j = callback.get(Defaults_1.CALLBACK_KEY.ON_CONNECTED)) === null || _j === void 0 ? void 0 : _j(sessionId);
424
+ (_k = options.onConnected) === null || _k === void 0 ? void 0 : _k.call(options);
425
+ }
426
+ }
427
+ if (events["creds.update"]) {
428
+ yield saveCreds();
429
+ }
430
+ // Menangani event update data grup
431
+ if (events["groups.update"]) {
432
+ const updates = events["groups.update"];
433
+ for (const update of updates) {
434
+ try {
435
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
436
+ const metadata = yield sock.groupMetadata(update.id);
437
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
438
+ }
439
+ catch (error) {
440
+ console.error(`Error updating group metadata in cache: ${error}`);
441
+ }
442
+ }
443
+ }
444
+ // Menangani event perubahan peserta grup
445
+ if (events["group-participants.update"]) {
446
+ const update = events["group-participants.update"];
447
+ try {
448
+ // Dapatkan metadata grup terbaru dan simpan ke cache dengan sessionId
449
+ const metadata = yield sock.groupMetadata(update.id);
450
+ yield Utils_1.groupCache.set(sessionId, update.id, metadata);
451
+ }
452
+ catch (error) {
453
+ console.error(`Error updating group participants in cache: ${error}`);
454
+ }
455
+ }
456
+ if (events["messages.update"]) {
457
+ const msg = events["messages.update"][0];
458
+ const data = Object.assign({ sessionId: sessionId, messageStatus: (0, message_status_1.parseMessageStatusCodeToReadable)(msg.update.status) }, msg);
459
+ (_l = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED)) === null || _l === void 0 ? void 0 : _l(sessionId, data);
460
+ (_m = options.onMessageUpdated) === null || _m === void 0 ? void 0 : _m.call(options, data);
461
+ }
462
+ if (events["messages.upsert"]) {
463
+ const messages = events["messages.upsert"].messages || [];
464
+ for (const rawMsg of messages) {
465
+ // Skip protocol messages and system messages
466
+ if ((_o = rawMsg.message) === null || _o === void 0 ? void 0 : _o.protocolMessage) {
467
+ continue;
468
+ }
469
+ // Skip messages without content
470
+ if (!rawMsg.message || Object.keys(rawMsg.message).length === 0) {
471
+ continue;
472
+ }
473
+ const msg = rawMsg;
474
+ msg.sessionId = sessionId;
475
+ msg.saveImage = (path) => (0, save_media_1.saveImageHandler)(msg, path);
476
+ msg.saveVideo = (path) => (0, save_media_1.saveVideoHandler)(msg, path);
477
+ msg.saveDocument = (path) => (0, save_media_1.saveDocumentHandler)(msg, path);
478
+ msg.saveAudio = (path) => (0, save_media_1.saveAudioHandler)(msg, path);
479
+ (_p = callback.get(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED)) === null || _p === void 0 ? void 0 : _p(Object.assign({}, msg));
480
+ (_q = options.onMessageReceived) === null || _q === void 0 ? void 0 : _q.call(options, msg);
481
+ }
482
+ }
483
+ }));
484
+ return sock;
485
+ }
486
+ catch (error) {
487
+ // console.log("SOCKET ERROR", error);
488
+ return sock;
489
+ }
490
+ });
491
+ return startSocket();
492
+ });
493
+ exports.startSessionWithPairingCode = startSessionWithPairingCode;
494
+ /**
495
+ * @deprecated Use startSession method instead
496
+ */
497
+ exports.startWhatsapp = exports.startSession;
498
+ /**
499
+ * Soft delete session - removes from memory but preserves MongoDB data for pairing code sessions
500
+ * @param sessionId Session ID to soft delete
501
+ */
502
+ const softDeleteSession = (sessionId_1, ...args_1) => __awaiter(void 0, [sessionId_1, ...args_1], void 0, function* (sessionId, preserveData = false) {
503
+ const session = (0, exports.getSession)(sessionId);
504
+ try {
505
+ yield (session === null || session === void 0 ? void 0 : session.logout());
506
+ }
507
+ catch (error) { }
508
+ session === null || session === void 0 ? void 0 : session.end(undefined);
509
+ sessions.delete(sessionId);
510
+ // Only completely remove from MongoDB if not preserving data or not a pairing code session
511
+ if (!preserveData && !pairingCodeSessions.has(sessionId)) {
512
+ if (authCollection) {
513
+ try {
514
+ yield authCollection.deleteOne({ sessionId });
515
+ }
516
+ catch (error) {
517
+ console.error(`Error deleting session ${sessionId} from MongoDB:`, error);
518
+ }
519
+ }
520
+ }
521
+ else if (pairingCodeSessions.has(sessionId)) {
522
+ // Preserving MongoDB data for pairing code session
523
+ }
524
+ // Hapus cache grup untuk session ini
525
+ try {
526
+ yield Utils_1.groupCache.clearSessionCache(sessionId);
527
+ }
528
+ catch (error) {
529
+ console.error(`Error clearing group cache for session ${sessionId}:`, error);
530
+ }
531
+ // Legacy: hapus juga dari file system jika ada
532
+ const dir = path_1.default.resolve(Defaults_1.CREDENTIALS.DIR_NAME, sessionId + Defaults_1.CREDENTIALS.PREFIX);
533
+ if (fs_1.default.existsSync(dir)) {
534
+ fs_1.default.rmSync(dir, { force: true, recursive: true });
535
+ }
536
+ });
537
+ const deleteSession = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
538
+ const session = (0, exports.getSession)(sessionId);
539
+ try {
540
+ yield (session === null || session === void 0 ? void 0 : session.logout());
541
+ }
542
+ catch (error) { }
543
+ session === null || session === void 0 ? void 0 : session.end(undefined);
544
+ sessions.delete(sessionId);
545
+ // Hapus tracking pairing code session jika ada
546
+ pairingCodeSessions.delete(sessionId);
547
+ // Hapus juga dari MongoDB jika authCollection ada
548
+ if (authCollection) {
549
+ try {
550
+ yield authCollection.deleteOne({ sessionId });
551
+ }
552
+ catch (error) {
553
+ console.error(`Error deleting session ${sessionId} from MongoDB:`, error);
554
+ }
555
+ }
556
+ // Hapus cache grup untuk session ini
557
+ try {
558
+ yield Utils_1.groupCache.clearSessionCache(sessionId);
559
+ }
560
+ catch (error) {
561
+ console.error(`Error clearing group cache for session ${sessionId}:`, error);
562
+ }
563
+ // Legacy: hapus juga dari file system jika ada
564
+ const dir = path_1.default.resolve(Defaults_1.CREDENTIALS.DIR_NAME, sessionId + Defaults_1.CREDENTIALS.PREFIX);
565
+ if (fs_1.default.existsSync(dir)) {
566
+ fs_1.default.rmSync(dir, { force: true, recursive: true });
567
+ }
568
+ });
569
+ exports.deleteSession = deleteSession;
570
+ /**
571
+ * Get all active session IDs
572
+ * @returns Array of session IDs
573
+ */
574
+ const getAllSession = () => __awaiter(void 0, void 0, void 0, function* () {
575
+ // Return active sessions from Map (sessions yang sudah running di memori)
576
+ const runningSessionIds = Array.from(sessions.keys());
577
+ // Jika authCollection belum diinisialisasi, kembalikan hanya sessions dari memori
578
+ if (!authCollection) {
579
+ return runningSessionIds;
580
+ }
581
+ try {
582
+ // Ambil semua sessionId dari MongoDB
583
+ const sessionDocs = yield authCollection.find({}).toArray();
584
+ const mongoSessionIds = sessionDocs.map((doc) => doc.sessionId);
585
+ // Gabungkan dan deduplikasi session IDs
586
+ const allSessionIds = [...new Set([...runningSessionIds, ...mongoSessionIds])];
587
+ return allSessionIds;
588
+ }
589
+ catch (error) {
590
+ console.error("Error fetching sessions from MongoDB:", error);
591
+ // Fallback ke sessions yang ada di memori jika MongoDB error
592
+ return runningSessionIds;
593
+ }
594
+ });
595
+ exports.getAllSession = getAllSession;
596
+ // Untuk backward compatibility
597
+ const getAllSessionSync = () => Array.from(sessions.keys());
598
+ exports.getAllSessionSync = getAllSessionSync;
599
+ const getSession = (key) => sessions.get(key);
600
+ exports.getSession = getSession;
601
+ const isSessionExistAndRunning = (sessionId) => {
602
+ // Cek jika session sudah berjalan di memory
603
+ if ((0, exports.getSession)(sessionId)) {
604
+ return true;
605
+ }
606
+ return false;
607
+ };
608
+ /**
609
+ * Check if session should be loaded
610
+ * @param sessionId Session ID to check
611
+ * @returns Boolean indicating if session should be loaded
612
+ */
613
+ const shouldLoadSession = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
614
+ // Jika session sudah berjalan di memory, tidak perlu load lagi
615
+ if ((0, exports.getSession)(sessionId)) {
616
+ return false;
617
+ }
618
+ // Jika authCollection belum diinisialisasi, tidak bisa load
619
+ if (!authCollection) {
620
+ return false;
621
+ }
622
+ try {
623
+ // Periksa apakah session ada di MongoDB
624
+ const sessionDoc = yield authCollection.findOne({ sessionId });
625
+ return !!sessionDoc; // Return true jika session ditemukan di MongoDB
626
+ }
627
+ catch (error) {
628
+ console.error(`Error checking session ${sessionId} in MongoDB:`, error);
629
+ return false;
630
+ }
631
+ });
632
+ /**
633
+ * @deprecated Use loadSessionsFromMongo instead
634
+ */
635
+ const loadSessionsFromStorage = () => {
636
+ console.warn("loadSessionsFromStorage is deprecated, use loadSessionsFromMongo instead");
637
+ // Redirect ke fungsi loadSessionsFromMongo untuk backward compatibility
638
+ (0, exports.loadSessionsFromMongo)().catch(err => {
639
+ console.error("Error loading sessions from MongoDB:", err);
640
+ });
641
+ };
642
+ exports.loadSessionsFromStorage = loadSessionsFromStorage;
643
+ const onMessageReceived = (listener) => {
644
+ callback.set(Defaults_1.CALLBACK_KEY.ON_MESSAGE_RECEIVED, listener);
645
+ };
646
+ exports.onMessageReceived = onMessageReceived;
647
+ const onQRUpdated = (listener) => {
648
+ callback.set(Defaults_1.CALLBACK_KEY.ON_QR, listener);
649
+ };
650
+ exports.onQRUpdated = onQRUpdated;
651
+ const onConnected = (listener) => {
652
+ callback.set(Defaults_1.CALLBACK_KEY.ON_CONNECTED, listener);
653
+ };
654
+ exports.onConnected = onConnected;
655
+ const onDisconnected = (listener) => {
656
+ callback.set(Defaults_1.CALLBACK_KEY.ON_DISCONNECTED, listener);
657
+ };
658
+ exports.onDisconnected = onDisconnected;
659
+ const onConnecting = (listener) => {
660
+ callback.set(Defaults_1.CALLBACK_KEY.ON_CONNECTING, listener);
661
+ };
662
+ exports.onConnecting = onConnecting;
663
+ const onMessageUpdate = (listener) => {
664
+ callback.set(Defaults_1.CALLBACK_KEY.ON_MESSAGE_UPDATED, listener);
665
+ };
666
+ exports.onMessageUpdate = onMessageUpdate;
667
+ const onPairingCode = (listener) => {
668
+ // Set callback ke registry dengan key yang benar
669
+ callback.set(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE, listener);
670
+ };
671
+ exports.onPairingCode = onPairingCode;
672
+ /**
673
+ * Load all sessions from MongoDB and start them automatically
674
+ */
675
+ const loadSessionsFromMongo = () => __awaiter(void 0, void 0, void 0, function* () {
676
+ yield initMongo();
677
+ const sessionDocs = yield authCollection.find({}).toArray();
678
+ for (const doc of sessionDocs) {
679
+ const sessionId = doc.sessionId;
680
+ if (sessionId && !(0, exports.getSession)(sessionId)) {
681
+ try {
682
+ yield (0, exports.startSession)(sessionId, { printQR: false });
683
+ }
684
+ catch (e) {
685
+ // Optional: log error jika gagal load session tertentu
686
+ console.error(`Failed to load session ${sessionId}:`, e);
687
+ }
688
+ }
689
+ }
690
+ });
691
+ exports.loadSessionsFromMongo = loadSessionsFromMongo;
692
+ /**
693
+ * Configure MongoDB database and collection names
694
+ *
695
+ * @param dbName MongoDB database name (default: "wa_session")
696
+ * @param collectionName MongoDB collection name for auth storage (default: "auth")
697
+ */
698
+ const setMongoDBNames = (dbName = "wa_session", collectionName = "auth") => {
699
+ Defaults_1.CREDENTIALS.MONGO_DB_NAME = dbName;
700
+ Defaults_1.CREDENTIALS.MONGO_COLLECTION_NAME = collectionName;
701
+ };
702
+ exports.setMongoDBNames = setMongoDBNames;
703
+ /**
704
+ * Sets the directory name for storing credentials (File-based storage)
705
+ *
706
+ * @deprecated When using MongoDB, this setting has no effect. Only used for legacy file-based storage.
707
+ * @param dirname Directory name for storing credentials (default: "wa_credentials")
708
+ */
709
+ const setCredentialsDir = (dirname = "wa_credentials") => {
710
+ console.warn("setCredentialsDir() is deprecated when using MongoDB storage. This setting only affects legacy file-based storage.");
711
+ Defaults_1.CREDENTIALS.DIR_NAME = dirname;
712
+ };
713
+ exports.setCredentialsDir = setCredentialsDir;
714
+ /**
715
+ * Attempt to reconnect a disconnected session
716
+ *
717
+ * @param sessionId Session ID to reconnect
718
+ * @returns Promise<boolean> indicating success
719
+ */
720
+ const reconnect = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
721
+ try {
722
+ // Cek jika session masih ada di memory
723
+ const existingSession = sessions.get(sessionId);
724
+ // Hapus session terlebih dahulu untuk menghindari konflik
725
+ if (existingSession) {
726
+ try {
727
+ // Coba lakukan logout jika memungkinkan (tapi jangan crash jika gagal)
728
+ yield existingSession.logout().catch((e) => { });
729
+ }
730
+ catch (logoutError) {
731
+ // Abaikan error saat logout
732
+ }
733
+ // Akhiri session dan hapus dari map secara paksa
734
+ try {
735
+ existingSession.end(undefined);
736
+ }
737
+ catch (endError) {
738
+ // Abaikan error saat mengakhiri
739
+ }
740
+ sessions.delete(sessionId);
741
+ }
742
+ // Tunggu sedikit waktu untuk memastikan cleanup selesai
743
+ yield (0, create_delay_1.createDelay)(1000);
744
+ // Cek jika ini session pairing code dari tracking terlebih dahulu
745
+ const pairingInfo = pairingCodeSessions.get(sessionId);
746
+ if (pairingInfo) {
747
+ // Ini adalah session pairing code, gunakan metode pairing code untuk reconnect
748
+ try {
749
+ // Reset retry count untuk session ini
750
+ retryCount.delete(sessionId);
751
+ yield (0, exports.startSessionWithPairingCode)(sessionId, pairingInfo.phoneNumber, Object.assign(Object.assign({}, pairingInfo.options), { printQR: false,
752
+ // Tambahkan callback khusus untuk reconnect
753
+ onConnected: () => {
754
+ // Pairing code session reconnected successfully
755
+ }, onDisconnected: () => {
756
+ // Pairing code session disconnected after reconnect
757
+ } }));
758
+ // Periksa jika session berhasil dimulai
759
+ return !!(0, exports.getSession)(sessionId);
760
+ }
761
+ catch (startError) {
762
+ console.error(`Failed to reconnect pairing code session ${sessionId}:`, startError.message);
763
+ return false;
764
+ }
765
+ }
766
+ else {
767
+ // Cek jika data session tersedia di MongoDB untuk session biasa
768
+ yield initMongo();
769
+ const sessionExists = yield shouldLoadSession(sessionId);
770
+ if (sessionExists) {
771
+ // Session biasa, gunakan metode startSession normal
772
+ try {
773
+ yield (0, exports.startSession)(sessionId, {
774
+ printQR: false,
775
+ // Tambahkan callback khusus untuk reconnect
776
+ onConnected: () => {
777
+ // Session reconnected successfully
778
+ },
779
+ onDisconnected: () => {
780
+ // Session disconnected after reconnect
781
+ },
782
+ onQRUpdated: (qr) => {
783
+ // QR code updated for reconnecting session
784
+ }
785
+ });
786
+ // Periksa jika session berhasil dimulai
787
+ return !!(0, exports.getSession)(sessionId);
788
+ }
789
+ catch (startError) {
790
+ console.error(`Failed to reconnect session ${sessionId}:`, startError.message);
791
+ return false;
792
+ }
793
+ }
794
+ else {
795
+ // No session data found in MongoDB
796
+ return false;
797
+ }
798
+ }
799
+ }
800
+ catch (error) {
801
+ console.error(`Error during reconnect for session ${sessionId}:`, error.message);
802
+ return false;
803
+ }
804
+ });
805
+ exports.reconnect = reconnect;
806
+ /**
807
+ * Reconnect all pairing code sessions that are tracked
808
+ * Useful for bulk reconnection after system restart
809
+ */
810
+ const reconnectAllPairingCodeSessions = () => __awaiter(void 0, void 0, void 0, function* () {
811
+ const results = {};
812
+ for (const [sessionId, sessionInfo] of pairingCodeSessions.entries()) {
813
+ try {
814
+ const success = yield (0, exports.reconnect)(sessionId);
815
+ results[sessionId] = success;
816
+ // Add delay between reconnection attempts
817
+ yield (0, create_delay_1.createDelay)(2000);
818
+ }
819
+ catch (error) {
820
+ console.error(`Error reconnecting pairing code session ${sessionId}:`, error.message);
821
+ results[sessionId] = false;
822
+ }
823
+ }
824
+ return results;
825
+ });
826
+ exports.reconnectAllPairingCodeSessions = reconnectAllPairingCodeSessions;
827
+ /**
828
+ * Get all tracked pairing code sessions
829
+ * @returns Array of session IDs that were created with pairing code
830
+ */
831
+ const getPairingCodeSessions = () => {
832
+ return Array.from(pairingCodeSessions.keys());
833
+ };
834
+ exports.getPairingCodeSessions = getPairingCodeSessions;
835
+ /**
836
+ * Get session status information
837
+ * @param sessionId Session ID to check
838
+ * @returns Object with session status information
839
+ */
840
+ const getSessionStatus = (sessionId) => {
841
+ const isRunning = !!(0, exports.getSession)(sessionId);
842
+ const isPairingCodeSession = pairingCodeSessions.has(sessionId);
843
+ const retryAttempts = retryCount.get(sessionId) || 0;
844
+ return {
845
+ sessionId,
846
+ isRunning,
847
+ isPairingCodeSession,
848
+ retryAttempts,
849
+ hasCredentials: isRunning ? true : null // null means unknown when not running
850
+ };
851
+ };
852
+ exports.getSessionStatus = getSessionStatus;
853
+ // Fungsi baru untuk mendapatkan konfigurasi TTL cache grup
854
+ const setGroupCacheConfig = (options) => {
855
+ Utils_1.groupCache.setConfig(options);
856
+ };
857
+ exports.setGroupCacheConfig = setGroupCacheConfig;
858
+ // Fungsi baru untuk mendapatkan atau memuat data grup dengan multi-session support
859
+ const getGroupMetadata = (sessionId_1, jid_1, ...args_1) => __awaiter(void 0, [sessionId_1, jid_1, ...args_1], void 0, function* (sessionId, jid, forceFetch = false) {
860
+ // Get the session socket
861
+ const sock = (0, exports.getSession)(sessionId);
862
+ if (!sock) {
863
+ throw new Error_1.WhatsappError(Defaults_1.Messages.sessionNotFound(sessionId));
864
+ }
865
+ try {
866
+ // Jika forceFetch true, langsung ambil dari server dan update cache
867
+ if (forceFetch) {
868
+ const metadata = yield sock.groupMetadata(jid);
869
+ yield Utils_1.groupCache.set(sessionId, jid, metadata);
870
+ return metadata;
871
+ }
872
+ // Coba ambil dari cache dulu
873
+ const cachedData = yield Utils_1.groupCache.get(sessionId, jid);
874
+ if (cachedData) {
875
+ return cachedData;
876
+ }
877
+ // Jika tidak ada di cache, ambil dari server dan simpan ke cache
878
+ const metadata = yield sock.groupMetadata(jid);
879
+ yield Utils_1.groupCache.set(sessionId, jid, metadata);
880
+ return metadata;
881
+ }
882
+ catch (error) {
883
+ throw new Error_1.WhatsappError(`Failed to fetch group metadata: ${error.message || String(error)}`);
884
+ }
885
+ });
886
+ exports.getGroupMetadata = getGroupMetadata;
887
+ // Fungsi baru untuk menghapus cache grup tertentu
888
+ const clearGroupMetadataCache = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
889
+ yield Utils_1.groupCache.delete(sessionId, jid);
890
+ });
891
+ exports.clearGroupMetadataCache = clearGroupMetadataCache;
892
+ // Fungsi untuk membersihkan seluruh cache grup untuk session tertentu
893
+ const clearSessionGroupMetadataCache = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
894
+ yield Utils_1.groupCache.clearSessionCache(sessionId);
895
+ });
896
+ exports.clearSessionGroupMetadataCache = clearSessionGroupMetadataCache;
897
+ // Fungsi untuk membersihkan seluruh cache grup untuk semua session
898
+ const clearAllGroupMetadataCache = () => {
899
+ Utils_1.groupCache.flush();
900
+ };
901
+ exports.clearAllGroupMetadataCache = clearAllGroupMetadataCache;
902
+ /**
903
+ * Convert LID (Linked ID) to Phone Number (PN/JID)
904
+ *
905
+ * This function uses Baileys' internal signalRepository.lidMapping to retrieve
906
+ * the phone number associated with a given LID.
907
+ *
908
+ * @param sessionId - Session ID to use for conversion
909
+ * @param lid - The LID to convert (e.g., "1524746986546@lid")
910
+ * @returns Promise<LIDConversionResult> - Result object with the phone number or null if not found
911
+ *
912
+ * @example
913
+ * ```typescript
914
+ * const result = await whatsapp.getPNForLID("mysession", "1524746986546@lid");
915
+ * if (result.success && result.pn) {
916
+ * console.log(`Phone number: ${result.pn}`);
917
+ * } else {
918
+ * console.log("Phone number not found for this LID");
919
+ * }
920
+ * ```
921
+ *
922
+ * @note This function may return null for new contacts or when WhatsApp
923
+ * hasn't provided the LID-PN mapping yet. Not all LIDs have known phone numbers.
924
+ */
925
+ const getPNForLID = (sessionId, lid) => __awaiter(void 0, void 0, void 0, function* () {
926
+ var _a, _b;
927
+ const session = (0, exports.getSession)(sessionId);
928
+ if (!session) {
929
+ return {
930
+ success: false,
931
+ lid,
932
+ pn: null,
933
+ error: Defaults_1.Messages.sessionNotFound(sessionId)
934
+ };
935
+ }
936
+ try {
937
+ // Normalize LID format
938
+ let normalizedLid = lid;
939
+ if (!lid.includes('@lid')) {
940
+ normalizedLid = `${lid}@lid`;
941
+ }
942
+ // Access the signalRepository.lidMapping to get PN for LID
943
+ const signalRepo = session.signalRepository;
944
+ if (!signalRepo || !signalRepo.lidMapping) {
945
+ return {
946
+ success: false,
947
+ lid: normalizedLid,
948
+ pn: null,
949
+ error: "LID mapping not available in this session"
950
+ };
951
+ }
952
+ // Try to get the phone number for the LID
953
+ const pn = ((_b = (_a = signalRepo.lidMapping).getPNForLID) === null || _b === void 0 ? void 0 : _b.call(_a, normalizedLid)) || null;
954
+ return {
955
+ success: pn !== null,
956
+ lid: normalizedLid,
957
+ pn
958
+ };
959
+ }
960
+ catch (error) {
961
+ return {
962
+ success: false,
963
+ lid,
964
+ pn: null,
965
+ error: `Failed to convert LID to PN: ${error.message || String(error)}`
966
+ };
967
+ }
968
+ });
969
+ exports.getPNForLID = getPNForLID;
970
+ /**
971
+ * Convert Phone Number (PN/JID) to LID (Linked ID)
972
+ *
973
+ * This function uses Baileys' internal signalRepository.lidMapping to retrieve
974
+ * the LID associated with a given phone number.
975
+ *
976
+ * @param sessionId - Session ID to use for conversion
977
+ * @param pn - The phone number/JID to convert (e.g., "6281234567890" or "6281234567890@s.whatsapp.net")
978
+ * @returns Promise<PNConversionResult> - Result object with the LID or null if not found
979
+ *
980
+ * @example
981
+ * ```typescript
982
+ * const result = await whatsapp.getLIDForPN("mysession", "6281234567890");
983
+ * if (result.success && result.lid) {
984
+ * console.log(`LID: ${result.lid}`);
985
+ * } else {
986
+ * console.log("LID not found for this phone number");
987
+ * }
988
+ * ```
989
+ *
990
+ * @note This function may return null for contacts that haven't been encountered
991
+ * with their LID mapping yet.
992
+ */
993
+ const getLIDForPN = (sessionId, pn) => __awaiter(void 0, void 0, void 0, function* () {
994
+ var _a, _b;
995
+ const session = (0, exports.getSession)(sessionId);
996
+ if (!session) {
997
+ return {
998
+ success: false,
999
+ pn,
1000
+ lid: null,
1001
+ error: Defaults_1.Messages.sessionNotFound(sessionId)
1002
+ };
1003
+ }
1004
+ try {
1005
+ // Normalize PN format
1006
+ let normalizedPn = pn.replace(/\D/g, ''); // Remove non-digits
1007
+ if (!pn.includes('@s.whatsapp.net')) {
1008
+ normalizedPn = `${normalizedPn}@s.whatsapp.net`;
1009
+ }
1010
+ else {
1011
+ normalizedPn = pn;
1012
+ }
1013
+ // Access the signalRepository.lidMapping to get LID for PN
1014
+ const signalRepo = session.signalRepository;
1015
+ if (!signalRepo || !signalRepo.lidMapping) {
1016
+ return {
1017
+ success: false,
1018
+ pn: normalizedPn,
1019
+ lid: null,
1020
+ error: "LID mapping not available in this session"
1021
+ };
1022
+ }
1023
+ // Try to get the LID for the phone number
1024
+ const lid = ((_b = (_a = signalRepo.lidMapping).getLIDForPN) === null || _b === void 0 ? void 0 : _b.call(_a, normalizedPn)) || null;
1025
+ return {
1026
+ success: lid !== null,
1027
+ pn: normalizedPn,
1028
+ lid
1029
+ };
1030
+ }
1031
+ catch (error) {
1032
+ return {
1033
+ success: false,
1034
+ pn,
1035
+ lid: null,
1036
+ error: `Failed to convert PN to LID: ${error.message || String(error)}`
1037
+ };
1038
+ }
1039
+ });
1040
+ exports.getLIDForPN = getLIDForPN;
1041
+ /**
1042
+ * Get all known LID-PN mappings for a session
1043
+ *
1044
+ * This function retrieves all LID to phone number mappings that are currently
1045
+ * stored in the session's signal repository.
1046
+ *
1047
+ * @param sessionId - Session ID to get mappings from
1048
+ * @returns Promise<LIDMappingEntry[]> - Array of LID-PN mapping entries
1049
+ *
1050
+ * @example
1051
+ * ```typescript
1052
+ * const mappings = await whatsapp.getAllLIDMappings("mysession");
1053
+ * for (const mapping of mappings) {
1054
+ * console.log(`${mapping.lid} => ${mapping.pn}`);
1055
+ * }
1056
+ * ```
1057
+ *
1058
+ * @note This may return an empty array if no mappings are available yet.
1059
+ */
1060
+ const getAllLIDMappings = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
1061
+ const session = (0, exports.getSession)(sessionId);
1062
+ if (!session) {
1063
+ throw new Error_1.WhatsappError(Defaults_1.Messages.sessionNotFound(sessionId));
1064
+ }
1065
+ try {
1066
+ const signalRepo = session.signalRepository;
1067
+ if (!signalRepo || !signalRepo.lidMapping) {
1068
+ return [];
1069
+ }
1070
+ // Try to get all mappings if available
1071
+ const getAllMappings = signalRepo.lidMapping.getAll || signalRepo.lidMapping.getAllMappings;
1072
+ if (typeof getAllMappings === 'function') {
1073
+ const mappings = getAllMappings();
1074
+ if (Array.isArray(mappings)) {
1075
+ return mappings;
1076
+ }
1077
+ // If it's a Map or Object, convert to array
1078
+ if (mappings instanceof Map) {
1079
+ return Array.from(mappings.entries()).map(([lid, pn]) => ({ lid, pn: pn }));
1080
+ }
1081
+ if (typeof mappings === 'object') {
1082
+ return Object.entries(mappings).map(([lid, pn]) => ({ lid, pn: pn }));
1083
+ }
1084
+ }
1085
+ // Alternative: Try to access internal store directly
1086
+ const store = signalRepo.lidMapping.store || signalRepo.lidMapping._store;
1087
+ if (store) {
1088
+ if (store instanceof Map) {
1089
+ return Array.from(store.entries()).map(([lid, pn]) => ({ lid, pn: pn }));
1090
+ }
1091
+ if (typeof store === 'object') {
1092
+ return Object.entries(store).map(([lid, pn]) => ({ lid, pn: pn }));
1093
+ }
1094
+ }
1095
+ return [];
1096
+ }
1097
+ catch (error) {
1098
+ throw new Error_1.WhatsappError(`Failed to get LID mappings: ${error.message || String(error)}`);
1099
+ }
1100
+ });
1101
+ exports.getAllLIDMappings = getAllLIDMappings;
1102
+ /**
1103
+ * Check if a JID is in LID format
1104
+ *
1105
+ * @param jid - The JID to check
1106
+ * @returns boolean - True if the JID is in LID format
1107
+ *
1108
+ * @example
1109
+ * ```typescript
1110
+ * if (whatsapp.isLIDFormat("1524746986546@lid")) {
1111
+ * console.log("This is an LID");
1112
+ * }
1113
+ * ```
1114
+ */
1115
+ const isLIDFormat = (jid) => {
1116
+ return jid.includes('@lid');
1117
+ };
1118
+ exports.isLIDFormat = isLIDFormat;
1119
+ /**
1120
+ * Check if a JID is in Phone Number format (@s.whatsapp.net)
1121
+ *
1122
+ * @param jid - The JID to check
1123
+ * @returns boolean - True if the JID is in PN format
1124
+ *
1125
+ * @example
1126
+ * ```typescript
1127
+ * if (whatsapp.isPNFormat("6281234567890@s.whatsapp.net")) {
1128
+ * console.log("This is a phone number JID");
1129
+ * }
1130
+ * ```
1131
+ */
1132
+ const isPNFormat = (jid) => {
1133
+ return jid.includes('@s.whatsapp.net');
1134
+ };
1135
+ exports.isPNFormat = isPNFormat;
1136
+ /**
1137
+ * Smart convert any JID to phone number
1138
+ *
1139
+ * Automatically detects if the input is an LID and converts it to PN,
1140
+ * or returns the PN if already in PN format.
1141
+ *
1142
+ * @param sessionId - Session ID to use for conversion
1143
+ * @param jid - Any JID (LID or PN format)
1144
+ * @returns Promise<string | null> - Phone number or null if conversion failed
1145
+ *
1146
+ * @example
1147
+ * ```typescript
1148
+ * const pn = await whatsapp.toPhoneNumber("mysession", jid);
1149
+ * if (pn) {
1150
+ * console.log(`Phone number: ${pn}`);
1151
+ * }
1152
+ * ```
1153
+ */
1154
+ const toPhoneNumber = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
1155
+ // If already in PN format, return as-is
1156
+ if ((0, exports.isPNFormat)(jid)) {
1157
+ return jid;
1158
+ }
1159
+ // If it's an LID, try to convert
1160
+ if ((0, exports.isLIDFormat)(jid)) {
1161
+ const result = yield (0, exports.getPNForLID)(sessionId, jid);
1162
+ return result.pn;
1163
+ }
1164
+ // If it's a group or broadcast, return null
1165
+ if (jid.includes('@g.us') || jid.includes('@broadcast')) {
1166
+ return null;
1167
+ }
1168
+ // If it's just a number, format it as PN
1169
+ const phoneNumber = jid.replace(/\D/g, '');
1170
+ if (phoneNumber.length >= 10) {
1171
+ return `${phoneNumber}@s.whatsapp.net`;
1172
+ }
1173
+ return null;
1174
+ });
1175
+ exports.toPhoneNumber = toPhoneNumber;
1176
+ /**
1177
+ * Smart convert any JID to LID
1178
+ *
1179
+ * Automatically detects if the input is a PN and converts it to LID,
1180
+ * or returns the LID if already in LID format.
1181
+ *
1182
+ * @param sessionId - Session ID to use for conversion
1183
+ * @param jid - Any JID (LID or PN format)
1184
+ * @returns Promise<string | null> - LID or null if conversion failed
1185
+ *
1186
+ * @example
1187
+ * ```typescript
1188
+ * const lid = await whatsapp.toLID("mysession", "6281234567890@s.whatsapp.net");
1189
+ * if (lid) {
1190
+ * console.log(`LID: ${lid}`);
1191
+ * }
1192
+ * ```
1193
+ */
1194
+ const toLID = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
1195
+ // If already in LID format, return as-is
1196
+ if ((0, exports.isLIDFormat)(jid)) {
1197
+ return jid;
1198
+ }
1199
+ // If it's a PN, try to convert
1200
+ if ((0, exports.isPNFormat)(jid) || /^\d+$/.test(jid.replace(/\D/g, ''))) {
1201
+ const result = yield (0, exports.getLIDForPN)(sessionId, jid);
1202
+ return result.lid;
1203
+ }
1204
+ // If it's a group or broadcast, return null
1205
+ if (jid.includes('@g.us') || jid.includes('@broadcast')) {
1206
+ return null;
1207
+ }
1208
+ return null;
1209
+ });
1210
+ exports.toLID = toLID;