@manybot/manybot 5.9.1 → 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.
@@ -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: 0,
990
+ timestamp: quotedTimestamp,
945
991
  body: decoded.body,
946
992
  mimetype: decoded.mimetype,
947
- fromPn: contextInfo.participant ?? undefined,
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
- id: msg.quotedKey.id ?? "",
967
- chatId: msg.chatId,
968
- fromMe: false,
969
- type: "other",
970
- contentHash: "",
971
- timestamp: 0,
972
- fromPn: msg.quotedKey.participant ?? undefined,
973
- pushName: lookupPushName(msg.quotedKey.participant),
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,
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "SyntaxError!",
6
6
  "email": "me@stxerr.dev"
7
7
  },
8
- "version": "5.9.1",
8
+ "version": "5.9.2",
9
9
  "license": "GPL-3.0-only",
10
10
  "private": false,
11
11
  "engines": {