@aunucore/baileys 1.0.85 → 1.0.86
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/lib/Socket/aunu-experimental.js +42 -8
- package/lib/Socket/chats.js +19 -2
- package/lib/Socket/messages-recv.js +14 -1
- package/lib/Socket/messages-send.js +11 -1
- package/lib/Socket/newsletter.d.ts +1 -1
- package/lib/Socket/newsletter.js +7 -1
- package/lib/Store/make-in-memory-store.js +7 -0
- package/lib/Utils/event-buffer.js +67 -15
- package/lib/Utils/history.js +11 -0
- package/lib/Utils/messages.js +15 -4
- package/lib/Utils/process-message.js +18 -6
- package/package.json +1 -1
|
@@ -5,6 +5,10 @@ import { generateWAMessageFromContent, prepareWAMessageMedia } from '../Utils/me
|
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
6
|
import { randomBytes } from 'crypto';
|
|
7
7
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
+
// AunuBaileys (1.0.86, HB-112 short series): Node clamps any
|
|
9
|
+
// setTimeout delay above 2^31-1 ms (~24.8 days) down to 1 ms, so
|
|
10
|
+
// a longer delay must be armed in slices of at most this size.
|
|
11
|
+
const MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
|
|
8
12
|
/**
|
|
9
13
|
* AunuBaileys EXPERIMENTAL socket features — these exist only in
|
|
10
14
|
* AunuBaileys and may change or disappear in any release:
|
|
@@ -125,7 +129,8 @@ export const attachAunuExperimental = (sock) => {
|
|
|
125
129
|
sock.aunuSchedule = (jid, content, when, options = {}) => {
|
|
126
130
|
const at = when instanceof Date ? when.getTime() : Date.now() + Math.max(0, Number(when) || 0);
|
|
127
131
|
const id = `aunu-sched-${++seq}`;
|
|
128
|
-
const
|
|
132
|
+
const entry = { jid, at, timer: undefined };
|
|
133
|
+
const fire = () => {
|
|
129
134
|
scheduled.delete(id);
|
|
130
135
|
// AunuBaileys (1.0.72): failures used to be swallowed by
|
|
131
136
|
// an empty catch — a scheduled message that failed (socket
|
|
@@ -133,9 +138,23 @@ export const attachAunuExperimental = (sock) => {
|
|
|
133
138
|
Promise.resolve(sock.sendMessage(jid, content, options)).catch((err) => {
|
|
134
139
|
logger?.warn?.({ err, jid, id }, 'aunu: scheduled message failed to send');
|
|
135
140
|
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
};
|
|
142
|
+
// AunuBaileys (1.0.86, HB-112 short series): arm in slices.
|
|
143
|
+
// A single setTimeout for a send scheduled more than ~24.8
|
|
144
|
+
// days out used to be clamped by Node to 1 ms, so the
|
|
145
|
+
// message fired IMMEDIATELY and the entry vanished as if
|
|
146
|
+
// sent on schedule. entry.timer always holds the CURRENT
|
|
147
|
+
// slice's handle, so cancel and socket-end cleanup (which
|
|
148
|
+
// read entry.timer) keep working unchanged.
|
|
149
|
+
const arm = () => {
|
|
150
|
+
const remaining = at - Date.now();
|
|
151
|
+
entry.timer = remaining > MAX_TIMER_DELAY_MS
|
|
152
|
+
? setTimeout(arm, MAX_TIMER_DELAY_MS)
|
|
153
|
+
: setTimeout(fire, Math.max(0, remaining));
|
|
154
|
+
entry.timer.unref?.();
|
|
155
|
+
};
|
|
156
|
+
arm();
|
|
157
|
+
scheduled.set(id, entry);
|
|
139
158
|
return { id, at, cancel: () => sock.aunuCancelScheduled(id) };
|
|
140
159
|
};
|
|
141
160
|
sock.aunuCancelScheduled = (id) => {
|
|
@@ -152,14 +171,29 @@ export const attachAunuExperimental = (sock) => {
|
|
|
152
171
|
const sent = await sock.sendMessage(jid, content, options);
|
|
153
172
|
const key = sent?.key;
|
|
154
173
|
if (key?.id) {
|
|
155
|
-
|
|
174
|
+
// AunuBaileys (1.0.86, HB-112 short series): same
|
|
175
|
+
// slice-arming as aunuSchedule — a self-destruct set
|
|
176
|
+
// more than ~24.8 days out used to be clamped by Node
|
|
177
|
+
// to 1 ms and deleted the message almost immediately
|
|
178
|
+
// after it was sent. The map always holds the current
|
|
179
|
+
// slice's handle, so cancel and socket-end cleanup are
|
|
180
|
+
// unchanged.
|
|
181
|
+
const fireAt = Date.now() + Math.max(0.05, Number(seconds) || 0) * 1000;
|
|
182
|
+
const fire = () => {
|
|
156
183
|
destructs.delete(key.id);
|
|
157
184
|
Promise.resolve(sock.sendMessage(jid, { delete: key })).catch((err) => {
|
|
158
185
|
logger?.warn?.({ err, jid, id: key.id }, 'aunu: self-destruct delete failed');
|
|
159
186
|
});
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
187
|
+
};
|
|
188
|
+
const arm = () => {
|
|
189
|
+
const remaining = fireAt - Date.now();
|
|
190
|
+
const timer = remaining > MAX_TIMER_DELAY_MS
|
|
191
|
+
? setTimeout(arm, MAX_TIMER_DELAY_MS)
|
|
192
|
+
: setTimeout(fire, Math.max(0, remaining));
|
|
193
|
+
timer.unref?.();
|
|
194
|
+
destructs.set(key.id, timer);
|
|
195
|
+
};
|
|
196
|
+
arm();
|
|
163
197
|
}
|
|
164
198
|
return sent;
|
|
165
199
|
};
|
package/lib/Socket/chats.js
CHANGED
|
@@ -906,16 +906,33 @@ export const makeChatsSocket = (config) => {
|
|
|
906
906
|
}
|
|
907
907
|
}
|
|
908
908
|
const historyMsg = getHistoryMsg(msg.message);
|
|
909
|
-
|
|
909
|
+
// AunuBaileys (1.0.86, HB-113 short series): the
|
|
910
|
+
// shouldSyncHistoryMessage preference governs PASSIVE sync
|
|
911
|
+
// only. An ON_DEMAND payload is the answer to an explicit
|
|
912
|
+
// host request (fetchMessageHistory /
|
|
913
|
+
// requestPlaceholderResend); the single shared gate used
|
|
914
|
+
// to discard it silently whenever the preference was off
|
|
915
|
+
// — including the syncFullHistory:false default — so the
|
|
916
|
+
// host's request vanished without an error and without
|
|
917
|
+
// the messaging-history.set event. The initial-sync state
|
|
918
|
+
// machine below keeps the preference-based predicate
|
|
919
|
+
// (syncPreferenceAllows): on-demand responses must not
|
|
920
|
+
// drive it. For every non-ON_DEMAND input, and for
|
|
921
|
+
// ON_DEMAND with the preference on, syncPreferenceAllows
|
|
922
|
+
// equals the old gate exactly.
|
|
923
|
+
const syncPreferenceAllows = historyMsg
|
|
910
924
|
? shouldSyncHistoryMessage(historyMsg) && PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
|
|
911
925
|
: false;
|
|
926
|
+
const shouldProcessHistoryMsg = historyMsg?.syncType === proto.HistorySync.HistorySyncType.ON_DEMAND
|
|
927
|
+
? true
|
|
928
|
+
: syncPreferenceAllows;
|
|
912
929
|
// State machine: decide on sync and flush
|
|
913
930
|
if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
|
|
914
931
|
if (awaitingSyncTimeout) {
|
|
915
932
|
clearTimeout(awaitingSyncTimeout);
|
|
916
933
|
awaitingSyncTimeout = undefined;
|
|
917
934
|
}
|
|
918
|
-
if (
|
|
935
|
+
if (syncPreferenceAllows) {
|
|
919
936
|
syncState = SyncState.Syncing;
|
|
920
937
|
logger.info('Transitioned to Syncing state');
|
|
921
938
|
// Let doAppStateSync handle the final flush after it's done
|
|
@@ -1986,9 +1986,22 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1986
1986
|
msg.messageStubType = call.isVideo ? WAMessageStubType.CALL_MISSED_VIDEO : WAMessageStubType.CALL_MISSED_VOICE;
|
|
1987
1987
|
}
|
|
1988
1988
|
}
|
|
1989
|
-
else {
|
|
1989
|
+
else if (call.id) {
|
|
1990
1990
|
msg.message = { call: { callKey: Buffer.from(call.id) } };
|
|
1991
1991
|
}
|
|
1992
|
+
else {
|
|
1993
|
+
// AunuBaileys (1.0.86, HB-216): a group call offer
|
|
1994
|
+
// without a call-id (an optional stanza attr the
|
|
1995
|
+
// decoder does not validate) made Buffer.from throw
|
|
1996
|
+
// a raw TypeError inside this listener; the throw
|
|
1997
|
+
// unwound the whole 'call' emit, so host listeners
|
|
1998
|
+
// registered after this one never saw the offer at
|
|
1999
|
+
// all. There is no call key to reference and the
|
|
2000
|
+
// message key would carry no id either — skip the
|
|
2001
|
+
// notification message; the 'call' event itself
|
|
2002
|
+
// still reaches every listener.
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
1992
2005
|
const protoMsg = proto.WebMessageInfo.fromObject(msg);
|
|
1993
2006
|
// AunuBaileys: this floated unawaited and uncaught — a
|
|
1994
2007
|
// rejection here was an unhandledRejection that could kill
|
|
@@ -279,7 +279,17 @@ export const makeMessagesSocket = (config) => {
|
|
|
279
279
|
try {
|
|
280
280
|
const { recipientJid: jid, ...patchedMessage } = patchedMessageWithJid;
|
|
281
281
|
if (!jid) {
|
|
282
|
-
return
|
|
282
|
+
// AunuBaileys (1.0.86, HB-136): this used to return
|
|
283
|
+
// {} — truthy, so it passed the filter below and
|
|
284
|
+
// counted as a SUCCESSFUL node. A patch whose every
|
|
285
|
+
// entry lacked a recipientJid therefore "sent" a
|
|
286
|
+
// stanza with an empty <participants> list and
|
|
287
|
+
// relayMessage resolved, instead of failing with
|
|
288
|
+
// 'All encryptions failed' (the encoder silently
|
|
289
|
+
// drops tag-less children, so the stanza really
|
|
290
|
+
// went out). Upstream returns null here — the same
|
|
291
|
+
// value the per-recipient catch below already uses.
|
|
292
|
+
return null;
|
|
283
293
|
}
|
|
284
294
|
const bytes = encodeWAMessage(patchedMessage);
|
|
285
295
|
let encResult;
|
|
@@ -22,7 +22,7 @@ export declare const makeNewsletterSocket: (sock: GroupsSocket) => {
|
|
|
22
22
|
subscribeNewsletterUpdates: (jid: string) => Promise<{
|
|
23
23
|
duration: string;
|
|
24
24
|
} | null>;
|
|
25
|
-
newsletterAdminCount: (jid: string) => Promise<number>;
|
|
25
|
+
newsletterAdminCount: (jid: string) => Promise<number | undefined>;
|
|
26
26
|
newsletterChangeOwner: (jid: string, newOwnerJid: string) => Promise<void>;
|
|
27
27
|
newsletterDemote: (jid: string, userJid: string) => Promise<void>;
|
|
28
28
|
newsletterDelete: (jid: string) => Promise<void>;
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -181,7 +181,13 @@ export const makeNewsletterSocket = (sock) => {
|
|
|
181
181
|
},
|
|
182
182
|
newsletterAdminCount: async (jid) => {
|
|
183
183
|
const response = await executeWMexQuery({ newsletter_id: jid }, QueryIds.ADMIN_COUNT, XWAPaths.xwa2_newsletter_admin_count);
|
|
184
|
-
|
|
184
|
+
// AunuBaileys (1.0.86, HB-111 short series): the guard in
|
|
185
|
+
// executeWMexQuery only rejects an UNDEFINED response —
|
|
186
|
+
// a GraphQL null for the admin path passes through
|
|
187
|
+
// verbatim, and this bare deref threw a raw TypeError at
|
|
188
|
+
// the host. A channel without admin info simply has no
|
|
189
|
+
// count to report.
|
|
190
|
+
return response?.admin_count;
|
|
185
191
|
},
|
|
186
192
|
newsletterChangeOwner: async (jid, newOwnerJid) => {
|
|
187
193
|
await executeWMexQuery({ newsletter_id: jid, user_id: newOwnerJid }, QueryIds.CHANGE_OWNER, XWAPaths.xwa2_newsletter_change_owner);
|
|
@@ -306,6 +306,13 @@ const makeInMemoryStore = ({ logger: _logger, chatKey, labelAssociationKey }) =>
|
|
|
306
306
|
});
|
|
307
307
|
ev.on('messages.reaction', (reactions) => {
|
|
308
308
|
for (const { key, reaction } of reactions) {
|
|
309
|
+
// AunuBaileys (1.0.86, HB-187 addendum): a key-less
|
|
310
|
+
// reaction (host-emitted, or delivered unbuffered)
|
|
311
|
+
// dereferenced key.remoteJid bare here and threw
|
|
312
|
+
// inside the listener. It has no target; skip it.
|
|
313
|
+
if (!key?.remoteJid) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
309
316
|
const obj = messages[key.remoteJid];
|
|
310
317
|
const msg = obj === null || obj === void 0 ? void 0 : obj.get(key.id);
|
|
311
318
|
if (msg) {
|
|
@@ -100,7 +100,7 @@ export const makeEventBuffer = (logger) => {
|
|
|
100
100
|
delete data.chatUpdates[update.id];
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
const
|
|
103
|
+
const consolidatedMaps = consolidateEvents(data);
|
|
104
104
|
// AunuBaileys (1.0.81, HB-166 + HB-224): swap the fresh
|
|
105
105
|
// buffer in BEFORE emitting, and guard the emit. The old
|
|
106
106
|
// order assigned `data = newData` after the emit, so
|
|
@@ -116,12 +116,14 @@ export const makeEventBuffer = (logger) => {
|
|
|
116
116
|
// paths (processNodeWithBuffer), where a throw became an
|
|
117
117
|
// uncaught exception / unhandled rejection.
|
|
118
118
|
data = newData;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
for (const consolidatedData of consolidatedMaps) {
|
|
120
|
+
if (Object.keys(consolidatedData).length) {
|
|
121
|
+
try {
|
|
122
|
+
ev.emit('event', consolidatedData);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
logger.error({ err }, 'error emitting flushed events');
|
|
126
|
+
}
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
logger.trace({ conditionalChatUpdatesLeft }, 'released buffered events');
|
|
@@ -433,6 +435,17 @@ eventData, logger) {
|
|
|
433
435
|
case 'messages.reaction':
|
|
434
436
|
const reactions = eventData;
|
|
435
437
|
for (const { key, reaction } of reactions) {
|
|
438
|
+
// AunuBaileys (1.0.86, HB-187): a reaction whose
|
|
439
|
+
// target key is missing (an optional proto field)
|
|
440
|
+
// used to throw a raw TypeError inside
|
|
441
|
+
// stringifyMessageKey — inside upsertMessage, after
|
|
442
|
+
// the delivery receipt had already been sent, so
|
|
443
|
+
// the stanza ALSO earned a NACK 500 and the
|
|
444
|
+
// reaction was lost. A key-less reaction has no
|
|
445
|
+
// target to attach to; skip it.
|
|
446
|
+
if (!key) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
436
449
|
const keyStr = stringifyMessageKey(key);
|
|
437
450
|
const existing = data.messageUpserts[keyStr];
|
|
438
451
|
if (existing) {
|
|
@@ -462,10 +475,15 @@ eventData, logger) {
|
|
|
462
475
|
const groupUpdates = eventData;
|
|
463
476
|
for (const update of groupUpdates) {
|
|
464
477
|
const id = update.id;
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
478
|
+
// AunuBaileys (1.0.86, HB-176): a second update for
|
|
479
|
+
// the same group inside one buffer window used to
|
|
480
|
+
// be discarded whole — the merge only ran when no
|
|
481
|
+
// update was stored yet, so a subject change
|
|
482
|
+
// followed by a description change delivered only
|
|
483
|
+
// the subject and the store kept stale metadata.
|
|
484
|
+
// Merge into the stored update, like chats.update
|
|
485
|
+
// and contacts.update already do.
|
|
486
|
+
data.groupUpdates[id] = Object.assign(data.groupUpdates[id] || {}, update);
|
|
469
487
|
}
|
|
470
488
|
break;
|
|
471
489
|
default:
|
|
@@ -507,6 +525,11 @@ eventData, logger) {
|
|
|
507
525
|
}
|
|
508
526
|
function consolidateEvents(data) {
|
|
509
527
|
const map = {};
|
|
528
|
+
// AunuBaileys (1.0.86, HB-159): extra maps emitted right after
|
|
529
|
+
// the main one (see the messages.upsert grouping below). The
|
|
530
|
+
// common single-type case leaves this empty and behaviour is
|
|
531
|
+
// exactly what it was before.
|
|
532
|
+
const extraMaps = [];
|
|
510
533
|
if (!data.historySets.empty) {
|
|
511
534
|
map['messaging-history.set'] = {
|
|
512
535
|
chats: Object.values(data.historySets.chats),
|
|
@@ -532,11 +555,40 @@ function consolidateEvents(data) {
|
|
|
532
555
|
}
|
|
533
556
|
const messageUpsertList = Object.values(data.messageUpserts);
|
|
534
557
|
if (messageUpsertList.length) {
|
|
535
|
-
|
|
558
|
+
// AunuBaileys (1.0.86, HB-159): the whole batch used to
|
|
559
|
+
// take the FIRST message's type. A live 'notify' message
|
|
560
|
+
// buffered behind offline 'append' messages (the initial
|
|
561
|
+
// offline drain, or a history resync racing live traffic)
|
|
562
|
+
// was delivered as 'append' — the store never created its
|
|
563
|
+
// chat, the unread count vanished, and hosts that only act
|
|
564
|
+
// on 'notify' never saw a live message. Group by type
|
|
565
|
+
// instead: same-type batches keep the single consolidated
|
|
566
|
+
// event; a mixed batch emits one messages.upsert per type
|
|
567
|
+
// (the extra maps flush right after the main one), every
|
|
568
|
+
// message keeping its own type, in arrival order.
|
|
569
|
+
const messagesByType = new Map();
|
|
570
|
+
for (const entry of messageUpsertList) {
|
|
571
|
+
const list = messagesByType.get(entry.type);
|
|
572
|
+
if (list) {
|
|
573
|
+
list.push(entry.message);
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
messagesByType.set(entry.type, [entry.message]);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
const [firstType, ...otherTypes] = [...messagesByType.keys()];
|
|
536
580
|
map['messages.upsert'] = {
|
|
537
|
-
messages:
|
|
538
|
-
type
|
|
581
|
+
messages: messagesByType.get(firstType),
|
|
582
|
+
type: firstType
|
|
539
583
|
};
|
|
584
|
+
for (const type of otherTypes) {
|
|
585
|
+
extraMaps.push({
|
|
586
|
+
'messages.upsert': {
|
|
587
|
+
messages: messagesByType.get(type),
|
|
588
|
+
type
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
540
592
|
}
|
|
541
593
|
const messageUpdateList = Object.values(data.messageUpdates);
|
|
542
594
|
if (messageUpdateList.length) {
|
|
@@ -566,7 +618,7 @@ function consolidateEvents(data) {
|
|
|
566
618
|
if (groupUpdateList.length) {
|
|
567
619
|
map['groups.update'] = groupUpdateList;
|
|
568
620
|
}
|
|
569
|
-
return map;
|
|
621
|
+
return [map, ...extraMaps];
|
|
570
622
|
}
|
|
571
623
|
function concatChats(a, b) {
|
|
572
624
|
if (b.unreadCount === null && // neutralize unread counter
|
package/lib/Utils/history.js
CHANGED
|
@@ -39,6 +39,17 @@ export const processHistoryMessage = (item) => {
|
|
|
39
39
|
delete chat.messages;
|
|
40
40
|
for (const item of msgs) {
|
|
41
41
|
const message = item.message;
|
|
42
|
+
// AunuBaileys (1.0.86, HB-181): HistorySyncMsg.
|
|
43
|
+
// message is an OPTIONAL proto field — a wrapper
|
|
44
|
+
// carrying only msgOrderId decodes with message
|
|
45
|
+
// === null, and the bare derefs below (starting
|
|
46
|
+
// at message.key) threw a TypeError that cost
|
|
47
|
+
// the WHOLE history chunk (every conversation
|
|
48
|
+
// in the blob was NACKed and lost), not just the
|
|
49
|
+
// empty entry. Skip the entry.
|
|
50
|
+
if (!message) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
42
53
|
messages.push(message);
|
|
43
54
|
if (!chat.messages?.length) {
|
|
44
55
|
// keep only the most recent message in the chat array
|
package/lib/Utils/messages.js
CHANGED
|
@@ -1334,6 +1334,15 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1334
1334
|
}
|
|
1335
1335
|
const innerMessage = normalizeMessageContent(message);
|
|
1336
1336
|
const key = getContentType(innerMessage);
|
|
1337
|
+
// AunuBaileys (1.0.86, HB-122): on the raw path the content
|
|
1338
|
+
// value can be a bare string ('conversation') or absent
|
|
1339
|
+
// entirely (key undefined). Quote and ephemeral contextInfo
|
|
1340
|
+
// can only be attached to an object-shaped value — the `in`
|
|
1341
|
+
// check and the property assignment below both threw raw
|
|
1342
|
+
// TypeErrors otherwise (Cannot use 'in' operator... /
|
|
1343
|
+
// Cannot create property 'contextInfo' on string...).
|
|
1344
|
+
const contextTarget = key ? innerMessage[key] : undefined;
|
|
1345
|
+
const canAttachContext = !!contextTarget && typeof contextTarget === 'object';
|
|
1337
1346
|
const timestamp = unixTimestampSeconds(options.timestamp);
|
|
1338
1347
|
const { quoted, userJid } = options;
|
|
1339
1348
|
if (quoted) {
|
|
@@ -1348,7 +1357,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1348
1357
|
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
1349
1358
|
delete quotedContent.contextInfo;
|
|
1350
1359
|
}
|
|
1351
|
-
const contextInfo = ('contextInfo' in
|
|
1360
|
+
const contextInfo = (canAttachContext && 'contextInfo' in contextTarget && contextTarget.contextInfo) || {};
|
|
1352
1361
|
contextInfo.participant = jidNormalizedUser(participant);
|
|
1353
1362
|
contextInfo.stanzaId = quoted.key.id;
|
|
1354
1363
|
contextInfo.quotedMessage = quotedMsg;
|
|
@@ -1360,9 +1369,9 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1360
1369
|
if (!isJidNewsletter(jid) && jid !== quoted.key.remoteJid) {
|
|
1361
1370
|
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
1362
1371
|
}
|
|
1363
|
-
if (contextInfo &&
|
|
1372
|
+
if (contextInfo && canAttachContext) {
|
|
1364
1373
|
/* @ts-ignore */
|
|
1365
|
-
|
|
1374
|
+
contextTarget.contextInfo = contextInfo;
|
|
1366
1375
|
}
|
|
1367
1376
|
}
|
|
1368
1377
|
if (
|
|
@@ -1373,7 +1382,9 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1373
1382
|
// already not converted to disappearing message
|
|
1374
1383
|
key !== 'ephemeralMessage' &&
|
|
1375
1384
|
// newsletters don't support ephemeral messages
|
|
1376
|
-
!isJidNewsletter(jid)
|
|
1385
|
+
!isJidNewsletter(jid) &&
|
|
1386
|
+
// and a string/absent content value cannot carry one (HB-122)
|
|
1387
|
+
canAttachContext) {
|
|
1377
1388
|
/* @ts-ignore */
|
|
1378
1389
|
innerMessage[key].contextInfo = {
|
|
1379
1390
|
...(innerMessage[key].contextInfo || {}),
|
|
@@ -284,12 +284,24 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
284
284
|
...content.reactionMessage,
|
|
285
285
|
key: message.key
|
|
286
286
|
};
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
287
|
+
// AunuBaileys (1.0.86, HB-187): reactionMessage.key is an
|
|
288
|
+
// optional proto field — a reaction without it used to be
|
|
289
|
+
// emitted with key === undefined and detonated downstream
|
|
290
|
+
// (the event-buffer append and the in-memory store both
|
|
291
|
+
// deref key.remoteJid) with a raw TypeError, AFTER the
|
|
292
|
+
// delivery receipt had already been sent: the stanza
|
|
293
|
+
// earned a NACK 500 on top of its receipt and the reaction
|
|
294
|
+
// was lost on every redelivery. The reaction has no
|
|
295
|
+
// target message, so there is nothing to attach it to —
|
|
296
|
+
// do not emit it at all.
|
|
297
|
+
if (content.reactionMessage.key) {
|
|
298
|
+
ev.emit('messages.reaction', [
|
|
299
|
+
{
|
|
300
|
+
reaction,
|
|
301
|
+
key: content.reactionMessage.key
|
|
302
|
+
}
|
|
303
|
+
]);
|
|
304
|
+
}
|
|
293
305
|
}
|
|
294
306
|
else if (message.messageStubType) {
|
|
295
307
|
const jid = message.key?.remoteJid;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aunucore/baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.86",
|
|
5
5
|
"description": "AunuBaileys — the self-healing WhatsApp Web API for Node.js. Bad MAC and \"2000 messages into the future\" errors repair themselves, LID and phone-number identities stay in sync, anti-ban is built in, pairing codes are custom — plus 29 experimental features no other Baileys fork ships: invisible watermarks, per-person tag-all cards, side-profile text, ghost mentions and more. ESM, CJS and full TypeScript types.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|