miaw-core 1.2.3 → 1.2.6

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 (83) hide show
  1. package/dist/cli/commands/group.js +1 -1
  2. package/dist/cli/commands/group.js.map +1 -1
  3. package/dist/cli/commands/index.js +10 -4
  4. package/dist/cli/commands/index.js.map +1 -1
  5. package/dist/cli/repl.d.ts.map +1 -1
  6. package/dist/cli/repl.js +15 -0
  7. package/dist/cli/repl.js.map +1 -1
  8. package/dist/cli/utils/session.d.ts +1 -1
  9. package/dist/cli/utils/session.d.ts.map +1 -1
  10. package/dist/cli/utils/session.js +4 -2
  11. package/dist/cli/utils/session.js.map +1 -1
  12. package/dist/client/MiawClient.d.ts +12 -0
  13. package/dist/client/MiawClient.d.ts.map +1 -1
  14. package/dist/client/MiawClient.js +119 -60
  15. package/dist/client/MiawClient.js.map +1 -1
  16. package/dist/handlers/MessageHandler.d.ts +6 -0
  17. package/dist/handlers/MessageHandler.d.ts.map +1 -1
  18. package/dist/handlers/MessageHandler.js +13 -0
  19. package/dist/handlers/MessageHandler.js.map +1 -1
  20. package/dist/types/index.d.ts +2 -0
  21. package/dist/types/index.d.ts.map +1 -1
  22. package/dist/types/index.js.map +1 -1
  23. package/docs/CLI_INTEGRATION_TEST_PLAN.md +265 -0
  24. package/package.json +2 -1
  25. package/sessions-cli/.cli_history +82 -0
  26. package/sessions-cli/default/app-state-sync-version-regular.json +1 -1
  27. package/sessions-cli/default/app-state-sync-version-regular_high.json +1 -1
  28. package/sessions-cli/default/app-state-sync-version-regular_low.json +1 -1
  29. package/sessions-cli/default/chats.json +39 -6
  30. package/sessions-cli/default/contacts.json +88 -0
  31. package/sessions-cli/default/creds.json +1 -1
  32. package/sessions-cli/default/lid-mapping-144530112270579_reverse.json +1 -0
  33. package/sessions-cli/default/lid-mapping-177919053803568_reverse.json +1 -0
  34. package/sessions-cli/default/lid-mapping-197070984101964_reverse.json +1 -0
  35. package/sessions-cli/default/lid-mapping-198303270604941_reverse.json +1 -0
  36. package/sessions-cli/default/lid-mapping-2061584318613_reverse.json +1 -0
  37. package/sessions-cli/default/lid-mapping-270819297075205_reverse.json +1 -0
  38. package/sessions-cli/default/lid-mapping-6281227800347.json +1 -0
  39. package/sessions-cli/default/lid-mapping-6282130035583.json +1 -0
  40. package/sessions-cli/default/lid-mapping-6285338155153.json +1 -0
  41. package/sessions-cli/default/lid-mapping-628551000185.json +1 -0
  42. package/sessions-cli/default/lid-mapping-6285792059652.json +1 -0
  43. package/sessions-cli/default/lid-mapping-6288991818160.json +1 -0
  44. package/sessions-cli/default/sender-key-120363039902323086@g.us--270819297075205_1--23.json +1 -0
  45. package/sessions-cli/default/sender-key-120363039902323086@g.us--42877077966917_1--0.json +1 -0
  46. package/sessions-cli/default/sender-key-120363039902323086@g.us--42877077966917_1--73.json +1 -0
  47. package/sessions-cli/default/session-106657023574039_1.0.json +1 -0
  48. package/sessions-cli/default/session-139964746592398_1.0.json +1 -0
  49. package/sessions-cli/default/session-142481379311646_1.0.json +1 -0
  50. package/sessions-cli/default/session-143199091859590_1.0.json +1 -0
  51. package/sessions-cli/default/session-171911065661513_1.0.json +1 -0
  52. package/sessions-cli/default/session-192259949609102_1.0.json +1 -0
  53. package/sessions-cli/default/session-197070984101964_1.0.json +1 -0
  54. package/sessions-cli/default/session-198303270604941_1.0.json +1 -0
  55. package/sessions-cli/default/session-199527202033812_1.0.json +1 -0
  56. package/sessions-cli/default/session-199866387066970_1.0.json +1 -0
  57. package/sessions-cli/default/session-2061584318613_1.0.json +1 -0
  58. package/sessions-cli/default/session-21844270784649_1.0.json +1 -0
  59. package/sessions-cli/default/session-221706329321492_1.0.json +1 -0
  60. package/sessions-cli/default/session-223733570633772_1.0.json +1 -0
  61. package/sessions-cli/default/session-248180524482638_1.0.json +1 -0
  62. package/sessions-cli/default/session-263728574541943_1.0.json +1 -1
  63. package/sessions-cli/default/session-264230716612829_1.0.json +1 -0
  64. package/sessions-cli/default/session-270819297075205_1.0.json +1 -0
  65. package/sessions-cli/default/session-270819297075205_1.23.json +1 -0
  66. package/sessions-cli/default/session-42877077966917_1.0.json +1 -1
  67. package/sessions-cli/default/session-42877077966917_1.73.json +1 -0
  68. package/sessions-cli/default/session-42877077966917_1.74.json +1 -0
  69. package/sessions-cli/default/session-61800770973904_1.0.json +1 -0
  70. package/sessions-cli/default/session-70484775448831_1.0.json +1 -0
  71. package/sessions-cli/default/session-72816909103207_1.0.json +1 -0
  72. package/sessions-cli/default/session-73057444090080_1.0.json +1 -0
  73. package/sessions-cli/default/tctoken-197070984101964@lid.json +1 -0
  74. package/sessions-cli/default/tctoken-198303270604941@lid.json +1 -0
  75. package/sessions-cli/default/tctoken-2061584318613@lid.json +1 -0
  76. package/sessions-cli/default/tctoken-6285338155153@s.whatsapp.net.json +1 -0
  77. package/sessions-cli/default/pre-key-16.json +0 -1
  78. package/sessions-cli/default/pre-key-18.json +0 -1
  79. package/sessions-cli/default/pre-key-32.json +0 -1
  80. package/sessions-cli/default/pre-key-46.json +0 -1
  81. package/sessions-cli/default/pre-key-59.json +0 -1
  82. package/sessions-cli/default/pre-key-79.json +0 -1
  83. package/sessions-cli/default/pre-key-80.json +0 -1
@@ -1,4 +1,4 @@
1
- import makeWASocket, { DisconnectReason, fetchLatestBaileysVersion, makeCacheableSignalKeyStore, Browsers, downloadMediaMessage, } from "@whiskeysockets/baileys";
1
+ import makeWASocket, { DisconnectReason, fetchLatestBaileysVersion, makeCacheableSignalKeyStore, Browsers, downloadMediaMessage, jidNormalizedUser, } from "@whiskeysockets/baileys";
2
2
  import { EventEmitter } from "node:events";
3
3
  import { createFilteredLogger } from "../utils/filtered-logger.js";
4
4
  import { enableConsoleFilter, disableConsoleFilter, } from "../utils/console-filter.js";
@@ -130,6 +130,7 @@ export class MiawClient extends EventEmitter {
130
130
  qrGracePeriod: options.qrGracePeriod || TIMEOUTS.QR_GRACE_PERIOD,
131
131
  qrScanTimeout: options.qrScanTimeout || TIMEOUTS.QR_SCAN_TIMEOUT,
132
132
  connectionTimeout: options.connectionTimeout || TIMEOUTS.CONNECTION_TIMEOUT,
133
+ syncFullHistory: options.syncFullHistory !== false,
133
134
  };
134
135
  // Use the initialized logger
135
136
  this.logger = logger;
@@ -191,15 +192,15 @@ export class MiawClient extends EventEmitter {
191
192
  },
192
193
  browser: Browsers.macOS("Desktop"), // Desktop for more history
193
194
  generateHighQualityLinkPreview: true,
194
- // Enable full history sync to populate stores
195
- syncFullHistory: true,
195
+ // Enable full history sync to populate stores (controlled by syncFullHistory option)
196
+ syncFullHistory: this.options.syncFullHistory,
196
197
  fireInitQueries: true,
197
198
  // Debug callback to see if history sync notifications are received
198
199
  shouldSyncHistoryMessage: (msg) => {
199
200
  if (debugMode) {
200
201
  logger.debug(`[shouldSyncHistoryMessage] syncType: ${msg.syncType}`);
201
202
  }
202
- return true; // Always sync
203
+ return this.options.syncFullHistory;
203
204
  },
204
205
  });
205
206
  // Register event handlers
@@ -375,6 +376,13 @@ export class MiawClient extends EventEmitter {
375
376
  }
376
377
  const normalized = MessageHandler.normalize({ messages: [msg], type: "notify" }, this.logger);
377
378
  if (normalized) {
379
+ // Resolve @lid JIDs to @s.whatsapp.net for consistent display
380
+ if (normalized.from) {
381
+ normalized.from = this.resolveLidToJid(normalized.from);
382
+ }
383
+ if (normalized.participant) {
384
+ normalized.participant = this.resolveLidToJid(normalized.participant);
385
+ }
378
386
  // Resolve senderPhone from LID if not available (WhatsApp privacy feature)
379
387
  if (!normalized.senderPhone) {
380
388
  if (normalized.isGroup && normalized.participant) {
@@ -632,10 +640,7 @@ export class MiawClient extends EventEmitter {
632
640
  */
633
641
  getPhoneFromJid(jid) {
634
642
  const resolved = this.resolveLidToJid(jid);
635
- if (resolved.endsWith("@s.whatsapp.net")) {
636
- return resolved.replace("@s.whatsapp.net", "");
637
- }
638
- return undefined;
643
+ return MessageHandler.formatJidToPhone(resolved);
639
644
  }
640
645
  /**
641
646
  * Manually register a LID to phone number mapping
@@ -701,16 +706,19 @@ export class MiawClient extends EventEmitter {
701
706
  }
702
707
  if (!jid)
703
708
  continue;
704
- // Extract phone number from JID
705
- const phone = jid.endsWith("@s.whatsapp.net")
706
- ? jid.replace("@s.whatsapp.net", "")
707
- : undefined;
709
+ // Extract phone number from JID (strips device suffix like :72)
710
+ const phone = MessageHandler.formatJidToPhone(jid);
708
711
  // Build contact info
709
712
  const contactInfo = {
710
713
  jid,
711
714
  phone,
712
715
  name: contact.name || contact.notify || contact.verifiedName || undefined,
713
716
  };
717
+ // Preserve existing name if new entry lacks one
718
+ const existing = this.contactsStore.get(jid);
719
+ if (existing?.name && !contactInfo.name) {
720
+ contactInfo.name = existing.name;
721
+ }
714
722
  // Update store with phone JID as primary key
715
723
  this.contactsStore.set(jid, contactInfo);
716
724
  // Also store by LID for lookup if available
@@ -751,10 +759,8 @@ export class MiawClient extends EventEmitter {
751
759
  this.addLidMapping(jid, chat.pnJid, "Chat");
752
760
  jid = chat.pnJid;
753
761
  }
754
- // Extract phone number from JID
755
- const phone = jid.endsWith("@s.whatsapp.net")
756
- ? jid.replace("@s.whatsapp.net", "")
757
- : undefined;
762
+ // Extract phone number from JID (strips device suffix like :72)
763
+ const phone = MessageHandler.formatJidToPhone(jid);
758
764
  // Build chat info with proper field mapping for proto.IConversation
759
765
  const chatInfo = {
760
766
  jid,
@@ -789,6 +795,13 @@ export class MiawClient extends EventEmitter {
789
795
  const normalized = MessageHandler.normalize({ messages: [msg], type: "notify" }, this.logger);
790
796
  if (!normalized)
791
797
  return;
798
+ // Resolve @lid JIDs to @s.whatsapp.net for consistent storage
799
+ if (normalized.from) {
800
+ normalized.from = this.resolveLidToJid(normalized.from);
801
+ }
802
+ if (normalized.participant) {
803
+ normalized.participant = this.resolveLidToJid(normalized.participant);
804
+ }
792
805
  const chatJid = normalized.from;
793
806
  if (!this.messagesStore.has(chatJid)) {
794
807
  this.messagesStore.set(chatJid, []);
@@ -1244,11 +1257,12 @@ export class MiawClient extends EventEmitter {
1244
1257
  if (this.connectionState !== "connected") {
1245
1258
  throw new Error(`Cannot get contact info. Connection state: ${this.connectionState}`);
1246
1259
  }
1247
- const jid = MessageHandler.formatPhoneToJid(jidOrPhone);
1260
+ const rawJid = MessageHandler.formatPhoneToJid(jidOrPhone);
1261
+ const jid = this.resolveLidToJid(rawJid);
1248
1262
  // Fetch status
1249
1263
  let status;
1250
1264
  try {
1251
- const statusResult = await this.socket.fetchStatus(jid);
1265
+ const statusResult = await this.socket.fetchStatus(rawJid);
1252
1266
  // fetchStatus returns an array, get first result
1253
1267
  const firstResult = Array.isArray(statusResult)
1254
1268
  ? statusResult[0]
@@ -1261,16 +1275,14 @@ export class MiawClient extends EventEmitter {
1261
1275
  // Check if business account
1262
1276
  let isBusiness = false;
1263
1277
  try {
1264
- const businessProfile = await this.socket.getBusinessProfile(jid);
1278
+ const businessProfile = await this.socket.getBusinessProfile(rawJid);
1265
1279
  isBusiness = !!businessProfile;
1266
1280
  }
1267
1281
  catch {
1268
1282
  // Not a business account or not available
1269
1283
  }
1270
- // Extract phone from JID
1271
- const phone = jid.endsWith("@s.whatsapp.net")
1272
- ? jid.replace("@s.whatsapp.net", "")
1273
- : undefined;
1284
+ // Extract phone from resolved JID (strips device suffix like :72)
1285
+ const phone = MessageHandler.formatJidToPhone(jid);
1274
1286
  return {
1275
1287
  jid,
1276
1288
  phone,
@@ -1349,7 +1361,7 @@ export class MiawClient extends EventEmitter {
1349
1361
  // Not a business account or not available
1350
1362
  }
1351
1363
  return {
1352
- jid,
1364
+ jid: resolvedJid,
1353
1365
  phone,
1354
1366
  name,
1355
1367
  status,
@@ -1430,24 +1442,34 @@ export class MiawClient extends EventEmitter {
1430
1442
  */
1431
1443
  async fetchAllContacts() {
1432
1444
  try {
1433
- // Map contacts and resolve any @lid JIDs that weren't resolved earlier
1434
- const contacts = Array.from(this.contactsStore.values()).map(contact => {
1435
- // If jid is @lid and phone is missing, try to resolve using LID cache
1445
+ // Deduplicate contacts by resolved JID, merging data (prefer entries with names)
1446
+ const uniqueContacts = new Map();
1447
+ for (const contact of this.contactsStore.values()) {
1448
+ // Resolve @lid JIDs using LID cache
1449
+ let resolved = contact;
1436
1450
  if (contact.jid.endsWith("@lid") && !contact.phone) {
1437
- const resolved = this.resolveLidToJid(contact.jid);
1438
- if (resolved !== contact.jid && resolved.endsWith("@s.whatsapp.net")) {
1439
- return {
1451
+ const resolvedJid = this.resolveLidToJid(contact.jid);
1452
+ if (resolvedJid !== contact.jid && resolvedJid.endsWith("@s.whatsapp.net")) {
1453
+ resolved = {
1440
1454
  ...contact,
1441
- jid: resolved,
1442
- phone: resolved.replace("@s.whatsapp.net", ""),
1455
+ jid: resolvedJid,
1456
+ phone: MessageHandler.formatJidToPhone(resolvedJid),
1443
1457
  };
1444
1458
  }
1445
1459
  }
1446
- return contact;
1447
- });
1460
+ const key = resolved.jid;
1461
+ const existing = uniqueContacts.get(key);
1462
+ if (!existing) {
1463
+ uniqueContacts.set(key, resolved);
1464
+ }
1465
+ else if (!existing.name && resolved.name) {
1466
+ // Merge: prefer the entry that has a name
1467
+ uniqueContacts.set(key, resolved);
1468
+ }
1469
+ }
1448
1470
  return {
1449
1471
  success: true,
1450
- contacts,
1472
+ contacts: Array.from(uniqueContacts.values()),
1451
1473
  };
1452
1474
  }
1453
1475
  catch (error) {
@@ -1475,11 +1497,11 @@ export class MiawClient extends EventEmitter {
1475
1497
  jid: g.id,
1476
1498
  name: g.subject,
1477
1499
  description: g.desc || undefined,
1478
- owner: g.owner || undefined,
1500
+ owner: g.owner ? this.resolveLidToJid(g.owner) : undefined,
1479
1501
  createdAt: g.creation,
1480
1502
  participantCount: g.participants?.length || 0,
1481
1503
  participants: g.participants?.map((p) => ({
1482
- jid: p.id,
1504
+ jid: this.resolveLidToJid(p.id),
1483
1505
  role: p.admin === "superadmin"
1484
1506
  ? "superadmin"
1485
1507
  : p.admin === "admin"
@@ -1514,14 +1536,14 @@ export class MiawClient extends EventEmitter {
1514
1536
  if (this.connectionState !== "connected") {
1515
1537
  throw new Error(`Cannot get own profile. Connection state: ${this.connectionState}`);
1516
1538
  }
1517
- const jid = this.socket.user?.id;
1518
- if (!jid) {
1539
+ const rawJid = this.socket.user?.id;
1540
+ if (!rawJid) {
1519
1541
  throw new Error("User ID not available");
1520
1542
  }
1521
- // Extract phone number from JID
1522
- const phone = jid.endsWith("@s.whatsapp.net")
1523
- ? jid.replace("@s.whatsapp.net", "")
1524
- : undefined;
1543
+ // Normalize JID (strips device suffix like :72)
1544
+ const jid = jidNormalizedUser(rawJid);
1545
+ // Extract phone number from normalized JID
1546
+ const phone = MessageHandler.formatJidToPhone(jid);
1525
1547
  // Get display name from socket user
1526
1548
  const name = this.socket.user?.name;
1527
1549
  // Fetch status
@@ -1661,7 +1683,7 @@ export class MiawClient extends EventEmitter {
1661
1683
  // Chat not in store, create minimal info
1662
1684
  chats.push({
1663
1685
  jid,
1664
- phone: jid.replace(/@s\.whatsapp\.net$/, ""),
1686
+ phone: MessageHandler.formatJidToPhone(jid),
1665
1687
  isGroup: jid.endsWith("@g.us"),
1666
1688
  });
1667
1689
  }
@@ -1768,7 +1790,14 @@ export class MiawClient extends EventEmitter {
1768
1790
  // Deduplicate by jid (Map may have same contact under multiple keys)
1769
1791
  const uniqueContacts = new Map();
1770
1792
  for (const contact of this.contactsStore.values()) {
1771
- if (contact.jid && !uniqueContacts.has(contact.jid)) {
1793
+ if (!contact.jid)
1794
+ continue;
1795
+ const existing = uniqueContacts.get(contact.jid);
1796
+ if (!existing) {
1797
+ uniqueContacts.set(contact.jid, contact);
1798
+ }
1799
+ else if (!existing.name && contact.name) {
1800
+ // Prefer entries with names
1772
1801
  uniqueContacts.set(contact.jid, contact);
1773
1802
  }
1774
1803
  }
@@ -2104,24 +2133,34 @@ export class MiawClient extends EventEmitter {
2104
2133
  */
2105
2134
  async fetchAllChats() {
2106
2135
  try {
2107
- // Map chats and resolve any @lid JIDs that weren't resolved earlier
2108
- const chats = Array.from(this.chatsStore.values()).map(chat => {
2109
- // If jid is @lid and phone is missing, try to resolve using LID cache
2136
+ // Deduplicate chats by resolved JID, merging data (prefer entries with names)
2137
+ const uniqueChats = new Map();
2138
+ for (const chat of this.chatsStore.values()) {
2139
+ // Resolve @lid JIDs using LID cache
2140
+ let resolved = chat;
2110
2141
  if (chat.jid.endsWith("@lid") && !chat.phone) {
2111
- const resolved = this.resolveLidToJid(chat.jid);
2112
- if (resolved !== chat.jid && resolved.endsWith("@s.whatsapp.net")) {
2113
- return {
2142
+ const resolvedJid = this.resolveLidToJid(chat.jid);
2143
+ if (resolvedJid !== chat.jid && resolvedJid.endsWith("@s.whatsapp.net")) {
2144
+ resolved = {
2114
2145
  ...chat,
2115
- jid: resolved,
2116
- phone: resolved.replace("@s.whatsapp.net", ""),
2146
+ jid: resolvedJid,
2147
+ phone: MessageHandler.formatJidToPhone(resolvedJid),
2117
2148
  };
2118
2149
  }
2119
2150
  }
2120
- return chat;
2121
- });
2151
+ const key = resolved.jid;
2152
+ const existing = uniqueChats.get(key);
2153
+ if (!existing) {
2154
+ uniqueChats.set(key, resolved);
2155
+ }
2156
+ else if (!existing.name && resolved.name) {
2157
+ // Merge: prefer the entry that has a name
2158
+ uniqueChats.set(key, resolved);
2159
+ }
2160
+ }
2122
2161
  return {
2123
2162
  success: true,
2124
- chats,
2163
+ chats: Array.from(uniqueChats.values()),
2125
2164
  };
2126
2165
  }
2127
2166
  catch (error) {
@@ -2154,7 +2193,7 @@ export class MiawClient extends EventEmitter {
2154
2193
  }
2155
2194
  const metadata = await this.socket.groupMetadata(groupJid);
2156
2195
  const participants = metadata.participants.map((p) => ({
2157
- jid: p.id,
2196
+ jid: this.resolveLidToJid(p.id),
2158
2197
  role: p.admin === "superadmin"
2159
2198
  ? "superadmin"
2160
2199
  : p.admin === "admin"
@@ -2165,7 +2204,7 @@ export class MiawClient extends EventEmitter {
2165
2204
  jid: metadata.id,
2166
2205
  name: metadata.subject,
2167
2206
  description: metadata.desc || undefined,
2168
- owner: metadata.owner || undefined,
2207
+ owner: metadata.owner ? this.resolveLidToJid(metadata.owner) : undefined,
2169
2208
  createdAt: metadata.creation,
2170
2209
  participantCount: metadata.participants.length,
2171
2210
  participants,
@@ -2559,7 +2598,7 @@ export class MiawClient extends EventEmitter {
2559
2598
  const formattedParticipants = participants.map((p) => MessageHandler.formatPhoneToJid(p));
2560
2599
  const metadata = await this.socket.groupCreate(name, formattedParticipants);
2561
2600
  const groupParticipants = metadata.participants.map((p) => ({
2562
- jid: p.id,
2601
+ jid: this.resolveLidToJid(p.id),
2563
2602
  role: p.admin === "superadmin"
2564
2603
  ? "superadmin"
2565
2604
  : p.admin === "admin"
@@ -2573,7 +2612,7 @@ export class MiawClient extends EventEmitter {
2573
2612
  jid: metadata.id,
2574
2613
  name: metadata.subject,
2575
2614
  description: metadata.desc || undefined,
2576
- owner: metadata.owner || undefined,
2615
+ owner: metadata.owner ? this.resolveLidToJid(metadata.owner) : undefined,
2577
2616
  createdAt: metadata.creation,
2578
2617
  participantCount: metadata.participants.length,
2579
2618
  participants: groupParticipants,
@@ -4360,6 +4399,26 @@ export class MiawClient extends EventEmitter {
4360
4399
  this.disableDebug();
4361
4400
  }
4362
4401
  }
4402
+ /**
4403
+ * Enable history sync for next connection
4404
+ */
4405
+ enableSync() {
4406
+ this.options.syncFullHistory = true;
4407
+ this.logger.info("History sync enabled (will take effect on next connect)");
4408
+ }
4409
+ /**
4410
+ * Disable history sync for next connection
4411
+ */
4412
+ disableSync() {
4413
+ this.options.syncFullHistory = false;
4414
+ this.logger.info("History sync disabled (will take effect on next connect)");
4415
+ }
4416
+ /**
4417
+ * Check if history sync is enabled
4418
+ */
4419
+ isSyncEnabled() {
4420
+ return this.options.syncFullHistory;
4421
+ }
4363
4422
  // TypeScript event emitter type safety
4364
4423
  on(event, listener) {
4365
4424
  return super.on(event, listener);