@manybot/manybot 5.3.2 → 5.3.3

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.
@@ -348,9 +348,8 @@ const log = {
348
348
  * @param {string} jid
349
349
  * @param {WAStoreContact} [info]
350
350
  */
351
- function mentionDisplayName(jid, info) {
352
- const number = jid.split("@")[0];
353
- return info?.name ?? info?.verifiedName ?? info?.notify ?? number;
351
+ function mentionDisplayName(jid) {
352
+ return jid.split("@")[0];
354
353
  }
355
354
  /**
356
355
  * Build a normalized contact object from a JID and optional store metadata.
@@ -410,7 +409,7 @@ async function normalizeContact(jid, info, botJid, sock) {
410
409
  isWAAccount,
411
410
  isUser: !jid.endsWith("@g.us"),
412
411
  isGroup: jid.endsWith("@g.us"),
413
- mention: { text: `@${mentionDisplayName(jid, info)}`, mentions: [jid] },
412
+ mention: { text: `@${mentionDisplayName(jid)}`, mentions: [toWireJid(jid)] },
414
413
  };
415
414
  }
416
415
  // ── Contact API ───────────────────────────────────────────────────────────────
@@ -765,60 +764,72 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
765
764
  return new MessageHandle((async () => {
766
765
  const quotedMsg = await resolveQuoted();
767
766
  const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
767
+ // mentions/linkPreview are part of the message CONTENT, not the send
768
+ // options — Baileys reads contextInfo.mentionedJid off the content
769
+ // object. Putting them on sendOpts (3rd arg) is silently ignored: the
770
+ // message sends fine, "@name" shows as plain text, and nobody actually
771
+ // gets tagged/notified.
772
+ const messageContent = { text: content };
768
773
  if (opts.linkPreview === false) {
769
- sendOpts.linkPreview = false;
774
+ messageContent.linkPreview = null;
770
775
  }
771
776
  if (opts.mentions?.length) {
772
- sendOpts.mentions = opts.mentions;
777
+ messageContent.mentions = await resolveMentionJids(sock, store, jid, opts.mentions);
773
778
  }
774
779
  await waitForSendSlot(normJid, { cooldown, jitter });
775
780
  await simulateState(toPresenceCapable(sock), jid, typingDuration(content), "typing");
776
- return sock.sendMessage(jid, { text: content }, sendOpts);
781
+ return sock.sendMessage(jid, messageContent, sendOpts);
777
782
  })(), sock, store, { cooldown, jitter });
778
783
  },
779
784
  image(filePath, caption = "", opts = {}) {
780
785
  return new MessageHandle((async () => {
781
786
  const quotedMsg = await resolveQuoted();
782
787
  const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
788
+ await waitForSendSlot(normJid, { cooldown, jitter });
789
+ await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
790
+ const buffer = await readFile(filePath);
791
+ // viewOnce/mentions are part of the message CONTENT — see note above.
792
+ const messageContent = { image: buffer, caption };
783
793
  if (opts.viewOnce) {
784
- sendOpts.viewOnce = true;
794
+ messageContent.viewOnce = true;
785
795
  }
786
796
  if (opts.mentions?.length) {
787
- sendOpts.mentions = opts.mentions;
797
+ messageContent.mentions = await resolveMentionJids(sock, store, jid, opts.mentions);
788
798
  }
789
- await waitForSendSlot(normJid, { cooldown, jitter });
790
- await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
791
- const buffer = await readFile(filePath);
792
- return sock.sendMessage(jid, { image: buffer, caption }, sendOpts);
799
+ return sock.sendMessage(jid, messageContent, sendOpts);
793
800
  })(), sock, store, { cooldown, jitter });
794
801
  },
795
802
  video(filePath, caption = "", opts = {}) {
796
803
  return new MessageHandle((async () => {
797
804
  const quotedMsg = await resolveQuoted();
798
805
  const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
806
+ await waitForSendSlot(normJid, { cooldown, jitter });
807
+ await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
808
+ const buffer = await readFile(filePath);
809
+ // viewOnce/mentions are part of the message CONTENT — see note above.
810
+ const messageContent = { video: buffer, caption };
799
811
  if (opts.viewOnce) {
800
- sendOpts.viewOnce = true;
812
+ messageContent.viewOnce = true;
801
813
  }
802
814
  if (opts.mentions?.length) {
803
- sendOpts.mentions = opts.mentions;
815
+ messageContent.mentions = await resolveMentionJids(sock, store, jid, opts.mentions);
804
816
  }
805
- await waitForSendSlot(normJid, { cooldown, jitter });
806
- await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
807
- const buffer = await readFile(filePath);
808
- return sock.sendMessage(jid, { video: buffer, caption }, sendOpts);
817
+ return sock.sendMessage(jid, messageContent, sendOpts);
809
818
  })(), sock, store, { cooldown, jitter });
810
819
  },
811
820
  audio(filePath, { asVoice = true, viewOnce = false } = {}) {
812
821
  return new MessageHandle((async () => {
813
822
  const quotedMsg = await resolveQuoted();
814
823
  const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
815
- if (viewOnce) {
816
- sendOpts.viewOnce = true;
817
- }
818
824
  await waitForSendSlot(normJid, { cooldown, jitter });
819
825
  await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "recording");
820
826
  const buffer = await readFile(filePath);
821
- return sock.sendMessage(jid, { audio: buffer, mimetype: "audio/mp4", ptt: asVoice }, sendOpts);
827
+ // viewOnce is part of the message CONTENT see note above.
828
+ const messageContent = { audio: buffer, mimetype: "audio/mp4", ptt: asVoice };
829
+ if (viewOnce) {
830
+ messageContent.viewOnce = true;
831
+ }
832
+ return sock.sendMessage(jid, messageContent, sendOpts);
822
833
  })(), sock, store, { cooldown, jitter });
823
834
  },
824
835
  sticker(source) {
@@ -953,32 +964,76 @@ function buildEventsApi(sock, pluginName) {
953
964
  * @param {WASocket} sock
954
965
  * @param {string|null} chatJid — raw JID of the current group (null in setup context)
955
966
  */
956
- function buildAdminApi(sock, chatJid) {
957
- /**
958
- * Normalize a participant identifier to the wire JID format WhatsApp's
959
- * servers require (`...@s.whatsapp.net`). `groupParticipantsUpdate()`
960
- * doesn't fail per-participant for a malformed entry the WHOLE IQ
961
- * query gets rejected by the server as a "bad-request" Boom error
962
- * before any per-participant status even exists. This silently broke
963
- * for the two most common inputs a plugin author reaches for:
964
- * - `contact.id` this framework's own normalized `@c.us` form
965
- * (see normalizeJid()/denormalizeJid()), which isn't wire-valid.
966
- * - a bare phone number (with or without "+", spaces or dashes),
967
- * which has no `@...` server segment at all.
968
- * Already-correct JIDs (`@s.whatsapp.net`, `@lid`, `@g.us`) pass through
969
- * unchanged.
970
- * @param {string} id
971
- */
972
- function toParticipantJid(id) {
973
- const trimmed = id.trim();
974
- if (/@(s\.whatsapp\.net|lid|g\.us)$/.test(trimmed))
975
- return trimmed;
976
- if (trimmed.endsWith("@c.us"))
977
- return denormalizeJid(trimmed);
978
- const digits = trimmed.replace(/\D/g, "");
979
- return `${digits}@s.whatsapp.net`;
967
+ /**
968
+ * Normalize any identifier to the wire JID format WhatsApp's servers and
969
+ * protocol actually expect (`...@s.whatsapp.net`). Used anywhere a JID is
970
+ * handed straight to Baileys — `groupParticipantsUpdate()` and message
971
+ * `mentions` both of which silently misbehave otherwise: a malformed
972
+ * group-update JID gets the whole IQ query rejected ("bad-request"), and
973
+ * a malformed mentions entry just doesn't tag/notify anyone (the message
974
+ * still sends fine, so it looks like nothing is wrong until you check).
975
+ * Handles this framework's own normalized `@c.us` form (`contact.id`,
976
+ * `getMsgSender()`'s output — see normalizeJid()/denormalizeJid()), a bare
977
+ * phone number (with or without "+", spaces or dashes), and already-valid
978
+ * wire JIDs (`@s.whatsapp.net`, `@lid`, `@g.us`), which pass through
979
+ * unchanged.
980
+ * @param {string} id
981
+ */
982
+ function toWireJid(id) {
983
+ const trimmed = id.trim();
984
+ if (/@(s\.whatsapp\.net|lid|g\.us)$/.test(trimmed))
985
+ return trimmed;
986
+ if (trimmed.endsWith("@c.us"))
987
+ return denormalizeJid(trimmed);
988
+ const digits = trimmed.replace(/\D/g, "");
989
+ return `${digits}@s.whatsapp.net`;
990
+ }
991
+ /**
992
+ * Resolve mentions to the exact JID form the destination group uses for
993
+ * that participant — not whatever store.resolveJid() happens to have
994
+ * mapped it to. A group can address a member via @lid even when we've
995
+ * separately learned their phone number; WhatsApp only tags/notifies a
996
+ * mention when the JID matches the group's own addressing for that
997
+ * member. DMs have no participant list to check against, so just wire-
998
+ * normalize as before (mentions aren't a real thing in DMs anyway).
999
+ */
1000
+ async function resolveMentionJids(sock, store, jid, mentions) {
1001
+ const result = [];
1002
+ for (const m of mentions) {
1003
+ const wire = toWireJid(m);
1004
+ if (wire)
1005
+ result.push(wire);
1006
+ const resolved = store.resolveJid(m);
1007
+ if (resolved && resolved !== m) {
1008
+ const resolvedWire = toWireJid(resolved);
1009
+ if (resolvedWire)
1010
+ result.push(resolvedWire);
1011
+ }
1012
+ }
1013
+ if (!jid.endsWith("@g.us")) {
1014
+ return Array.from(new Set(result.filter(Boolean)));
1015
+ }
1016
+ let meta;
1017
+ try {
1018
+ meta = await getGroupMetadataCached(sock, jid);
1019
+ }
1020
+ catch {
1021
+ return Array.from(new Set(result.filter(Boolean)));
980
1022
  }
981
- const norm = (v) => (Array.isArray(v) ? v : [v]).map(toParticipantJid);
1023
+ for (const m of mentions) {
1024
+ const wire = toWireJid(m);
1025
+ const resolved = normalizeJid(store.resolveJid(m));
1026
+ const match = meta.participants.find(p => toWireJid(p.id) === wire || normalizeJid(store.resolveJid(p.id)) === resolved);
1027
+ if (match) {
1028
+ const matchWire = toWireJid(match.id);
1029
+ if (matchWire)
1030
+ result.push(matchWire);
1031
+ }
1032
+ }
1033
+ return Array.from(new Set(result.filter(Boolean)));
1034
+ }
1035
+ function buildAdminApi(sock, chatJid) {
1036
+ const norm = (v) => (Array.isArray(v) ? v : [v]).map(toWireJid);
982
1037
  function requireChat() {
983
1038
  if (!chatJid)
984
1039
  throw new Error("This admin operation requires a runtime group context.");
package/dist/main.js CHANGED
File without changes
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "SyntaxError!",
6
6
  "email": "me@stxerr.dev"
7
7
  },
8
- "version": "5.3.2",
8
+ "version": "5.3.3",
9
9
  "license": "GPL-3.0-only",
10
10
  "private": false,
11
11
  "engines": {