@manybot/manybot 5.9.0 → 5.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drivers/baileys/api/index.js +104 -25
- package/package.json +1 -1
|
@@ -178,6 +178,37 @@ function getMsgSenderPn(msg) {
|
|
|
178
178
|
return normalizeJid(msg.chatId);
|
|
179
179
|
return null;
|
|
180
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Split a quoted message's `contextInfo.participant` into `fromLid`/`fromPn`
|
|
183
|
+
* the same way the adapter's `toBotMessage()` splits `key.participant` /
|
|
184
|
+
* `key.participantAlt` via `splitLidPn()` — see the comment there. Unlike
|
|
185
|
+
* the key, `contextInfo` carries only a single `participant` field (no
|
|
186
|
+
* companion "Alt"), and it holds whichever form matches the chat's current
|
|
187
|
+
* addressing mode: under the modern default "lid" mode that's the @lid
|
|
188
|
+
* form, under legacy "pn" mode it's the phone-number form. Blindly
|
|
189
|
+
* assigning it to `fromPn` (as the quoted-message synthetic used to)
|
|
190
|
+
* leaves `fromLid` unset — so `getMsgSender()` (which only reads
|
|
191
|
+
* `participantAlt`/`fromLid`) falls through to `null` — while
|
|
192
|
+
* `getMsgSenderPn()` happily normalizes and returns the @lid value
|
|
193
|
+
* verbatim, since it never checks the suffix. Route by suffix here, and
|
|
194
|
+
* fill in the other side from the store's learned LID<->PN mapping when
|
|
195
|
+
* one is known.
|
|
196
|
+
*/
|
|
197
|
+
function splitQuotedParticipant(store, participant) {
|
|
198
|
+
if (!participant)
|
|
199
|
+
return {};
|
|
200
|
+
if (participant.endsWith("@lid")) {
|
|
201
|
+
const resolved = store.resolveJid(participant);
|
|
202
|
+
return {
|
|
203
|
+
fromLid: participant,
|
|
204
|
+
fromPn: resolved !== participant ? resolved : undefined,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
fromLid: store.resolvePn(participant) ?? undefined,
|
|
209
|
+
fromPn: participant,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
181
212
|
/** Quoted-message metadata as the rest of the api uses it. */
|
|
182
213
|
function getQuotedContext(msg) {
|
|
183
214
|
if (!msg.quotedKey)
|
|
@@ -935,16 +966,33 @@ export function buildMessageContext(msg, contract, store, guardOptions = {}) {
|
|
|
935
966
|
const quotedRaw = contextInfo?.quotedMessage
|
|
936
967
|
? (() => {
|
|
937
968
|
const decoded = decodeContent(contextInfo.quotedMessage);
|
|
969
|
+
const { fromLid: quotedFromLid, fromPn: quotedFromPn } = splitQuotedParticipant(store, contextInfo.participant);
|
|
970
|
+
// contextInfo itself never carries the quoted message's original
|
|
971
|
+
// send time (WhatsApp's ContextInfo proto has no timestamp field —
|
|
972
|
+
// only stanzaId/participant/quotedMessage). Best-effort recover it
|
|
973
|
+
// from the message store, keyed by the same chatId+stanzaId, when
|
|
974
|
+
// the original is still cached (it usually is, since a reply
|
|
975
|
+
// almost always quotes a recent message in the same chat). Stays
|
|
976
|
+
// 0 — same as before — only when the original has aged out of the
|
|
977
|
+
// store's per-chat cap or the chat history hasn't been seen yet.
|
|
978
|
+
const quotedOriginal = contextInfo.stanzaId
|
|
979
|
+
? store.messages.get(msg.chatId)?.get(contextInfo.stanzaId)
|
|
980
|
+
: undefined;
|
|
981
|
+
const quotedTimestamp = quotedOriginal
|
|
982
|
+
? Number(quotedOriginal.messageTimestamp ?? 0) * 1000
|
|
983
|
+
: 0;
|
|
938
984
|
return {
|
|
939
985
|
id: contextInfo.stanzaId ?? "",
|
|
940
986
|
chatId: msg.chatId,
|
|
941
987
|
fromMe: false,
|
|
942
988
|
type: decoded.type,
|
|
943
989
|
contentHash: "",
|
|
944
|
-
timestamp:
|
|
990
|
+
timestamp: quotedTimestamp,
|
|
945
991
|
body: decoded.body,
|
|
946
992
|
mimetype: decoded.mimetype,
|
|
947
|
-
|
|
993
|
+
fromLid: quotedFromLid,
|
|
994
|
+
fromPn: quotedFromPn,
|
|
995
|
+
participantAlt: quotedFromLid,
|
|
948
996
|
pushName: lookupPushName(contextInfo.participant),
|
|
949
997
|
_raw: {
|
|
950
998
|
contextInfo: {
|
|
@@ -962,16 +1010,27 @@ export function buildMessageContext(msg, contract, store, guardOptions = {}) {
|
|
|
962
1010
|
// key-only synthetic so hasReply()/getReply() still work, but
|
|
963
1011
|
// hasMedia/downloadMedia on the result will degrade gracefully
|
|
964
1012
|
// (type=other, mimetype=undefined).
|
|
965
|
-
? {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1013
|
+
? (() => {
|
|
1014
|
+
const { fromLid: quotedFromLid, fromPn: quotedFromPn } = splitQuotedParticipant(store, msg.quotedKey.participant);
|
|
1015
|
+
const quotedOriginal = msg.quotedKey.id
|
|
1016
|
+
? store.messages.get(msg.chatId)?.get(msg.quotedKey.id)
|
|
1017
|
+
: undefined;
|
|
1018
|
+
const quotedTimestamp = quotedOriginal
|
|
1019
|
+
? Number(quotedOriginal.messageTimestamp ?? 0) * 1000
|
|
1020
|
+
: 0;
|
|
1021
|
+
return {
|
|
1022
|
+
id: msg.quotedKey.id ?? "",
|
|
1023
|
+
chatId: msg.chatId,
|
|
1024
|
+
fromMe: false,
|
|
1025
|
+
type: "other",
|
|
1026
|
+
contentHash: "",
|
|
1027
|
+
timestamp: quotedTimestamp,
|
|
1028
|
+
fromLid: quotedFromLid,
|
|
1029
|
+
fromPn: quotedFromPn,
|
|
1030
|
+
participantAlt: quotedFromLid,
|
|
1031
|
+
pushName: lookupPushName(msg.quotedKey.participant),
|
|
1032
|
+
};
|
|
1033
|
+
})()
|
|
975
1034
|
: null;
|
|
976
1035
|
return {
|
|
977
1036
|
id: msg.id,
|
|
@@ -1680,15 +1739,26 @@ function buildAdminApi(contract, store, chatJid) {
|
|
|
1680
1739
|
const botJid = me.id ? normalizeJid(jidNormalizedUser(me.id)) : null;
|
|
1681
1740
|
const botLid = me.lid ? normalizeJid(me.lid) : null;
|
|
1682
1741
|
/**
|
|
1683
|
-
* Resolve admin-supplied identifiers (bare phone number,
|
|
1684
|
-
* @s.whatsapp.net, or @lid) to the exact jid WhatsApp has on
|
|
1685
|
-
* that participant *in this group*. A naive toWireJid() guess
|
|
1686
|
-
* correct for pn-addressed groups — lid-addressed groups
|
|
1687
|
-
* common, e.g. when a member hides their phone number)
|
|
1688
|
-
* that member by @lid, which a phone number typed by
|
|
1689
|
-
* produce on its own. Baileys' raw groupMetadata()
|
|
1690
|
-
* `id` (whatever WA addresses them as here), `jid`
|
|
1691
|
-
* phone-number guess) and `lid` — check all three.
|
|
1742
|
+
* Resolve admin-supplied identifiers (bare phone number, bare LID,
|
|
1743
|
+
* @c.us, @s.whatsapp.net, or @lid) to the exact jid WhatsApp has on
|
|
1744
|
+
* file for that participant *in this group*. A naive toWireJid() guess
|
|
1745
|
+
* is only correct for pn-addressed groups — lid-addressed groups
|
|
1746
|
+
* (increasingly common, e.g. when a member hides their phone number)
|
|
1747
|
+
* only recognize that member by @lid, which a phone number typed by
|
|
1748
|
+
* the admin can't produce on its own. Baileys' raw groupMetadata()
|
|
1749
|
+
* participants carry `id` (whatever WA addresses them as here), `jid`
|
|
1750
|
+
* (its best phone-number guess) and `lid` — check all three.
|
|
1751
|
+
*
|
|
1752
|
+
* When the identifier has no explicit domain (the admin typed a bare
|
|
1753
|
+
* number), we don't know if it's a PN or a LID — toWireJid() would
|
|
1754
|
+
* silently guess PN, which never matches a participant that's only
|
|
1755
|
+
* addressable by @lid even when the digits are identical (e.g. typed
|
|
1756
|
+
* "118077710708981", the actual member is "118077710708981@lid"). In
|
|
1757
|
+
* that case, compare by digits alone against id/jid/lid instead of
|
|
1758
|
+
* forcing a domain. When the identifier *does* carry an explicit
|
|
1759
|
+
* domain (@c.us, @s.whatsapp.net, @lid), the domain is meaningful
|
|
1760
|
+
* (disambiguates a PN from a same-digit LID) and the original
|
|
1761
|
+
* wire/resolved comparison is used as before.
|
|
1692
1762
|
*
|
|
1693
1763
|
* Throws per-identifier if it doesn't match a current member, instead
|
|
1694
1764
|
* of silently sending a guessed jid that WhatsApp rejects deep inside
|
|
@@ -1698,14 +1768,23 @@ function buildAdminApi(contract, store, chatJid) {
|
|
|
1698
1768
|
const meta = await getGroupMetadataCached(contract, groupJid);
|
|
1699
1769
|
const out = [];
|
|
1700
1770
|
for (const id of identifiers) {
|
|
1771
|
+
const hasExplicitDomain = /@(s\.whatsapp\.net|lid|g\.us|c\.us)$/.test(id.trim());
|
|
1701
1772
|
const wire = toWireJid(id);
|
|
1702
1773
|
const resolved = normalizeJid(store.resolveJid(id));
|
|
1774
|
+
const idDigits = id.replace(/\D/g, "");
|
|
1703
1775
|
const match = meta.participants.find((p) => {
|
|
1704
1776
|
const pAny = p;
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1777
|
+
if (hasExplicitDomain) {
|
|
1778
|
+
return (toWireJid(pAny.id) === wire ||
|
|
1779
|
+
normalizeJid(store.resolveJid(pAny.id)) === resolved ||
|
|
1780
|
+
(pAny.jid ? toWireJid(pAny.jid) === wire : false) ||
|
|
1781
|
+
(pAny.lid ? toWireJid(pAny.lid) === wire : false));
|
|
1782
|
+
}
|
|
1783
|
+
// Bare number, no domain hint: match by digits against id/jid/lid,
|
|
1784
|
+
// instead of assuming a PN domain that may not be the one WhatsApp
|
|
1785
|
+
// actually uses for this participant (see PN-vs-LID note above).
|
|
1786
|
+
const cands = [pAny.id, pAny.jid, pAny.lid].filter((v) => !!v);
|
|
1787
|
+
return idDigits.length > 0 && cands.some((c) => c.replace(/\D/g, "") === idDigits);
|
|
1709
1788
|
});
|
|
1710
1789
|
if (!match) {
|
|
1711
1790
|
throw new Error(t("driver.groupParticipantNotFound", { id, group: groupJid }));
|