aunubaileys 1.0.49 β 1.0.51
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/README.md +8 -0
- package/lib/Signal/libsignal.js +21 -0
- package/lib/Socket/aunu-experimental.d.ts +39 -0
- package/lib/Socket/aunu-experimental.js +126 -0
- package/lib/Socket/index.js +39 -0
- package/lib/Types/Signal.d.ts +1 -0
- package/lib/Utils/auth-utils.js +13 -0
- package/lib/Utils/signal.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,14 @@ Everything else is pure upstream. When upstream moves, we rebase the patch layer
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
### π©Ή What's new in 1.0.51 / Baru di 1.0.51
|
|
68
|
+
|
|
69
|
+
- π **Three audited gaps, closed.** (1) **Key-store commit failures are no longer swallowed** (`auth-utils.js`): transaction commits still retry as before, but when every retry fails the error is now **thrown** β previously the mutations were silently discarded while the in-memory ratchet had already advanced, so every later message failed against the stale on-disk record. (2) **Hosted device :99 guard** (`signal.js`): `extractDeviceJids` now skips device 99 β hosted / Cloud-API companion devices are not E2E targets and libsignal rejects them when the device list is built. (3) **PN β LID session migration** (`libsignal.js`, `Socket/index.js`): the new repository method `migrateSession(fromJid, toJid)` moves the raw session record onto the LID address when the target has none (never overwrites). It fires automatically and best-effort when live traffic teaches a new PNβLID pair, and for the account's own session when the connection opens with both `me.id` and `me.lid` known. The 1.0.14β1.0.48 decrypt heals remain the safety net.
|
|
70
|
+
|
|
71
|
+
### π§ͺ What's new in 1.0.50 / Baru di 1.0.50 β EXPERIMENTAL
|
|
72
|
+
|
|
73
|
+
- π **Six more experimental features.** (1) `sock.aunuCard(jid, options)` β an interactive photo card: the header photo **does not open as a normal photo** when tapped, a title/name and text sit fused below it in the same bubble, and divider-separated buttons (`reply`/`url`/`copy`/`call`) sit underneath; the photo is uploaded from a Buffer/URL and embedded as the header, or supplied prebuilt as `imageMessage`. (2) `sock.aunuFakeQuote(jid, content, quote)` β send a message carrying a fabricated quote, as if replying to someone. (3) `sock.aunuTypewriter(jid, text, options)` β a typing effect: the message is sent in growing pieces by editing it on an interval until the full text stands. (4) `sock.aunuReactSequence(jid, key, emojis, options)` β cycle reactions on one message. (5) `sock.aunuPostStatus(text, options)` β a styled text status (background colour + font) in one call. (6) `sock.aunuPersonalCard(jid, targetJid, options)` β the one-person form of 1.0.49's personalised tag-all: an own-profile-picture + name card for a single target, into a chat or as a DM. All experimental, like the features of 1.0.47/1.0.49.
|
|
74
|
+
|
|
67
75
|
### π§ͺ What's new in 1.0.49 / Baru di 1.0.49 β EXPERIMENTAL
|
|
68
76
|
|
|
69
77
|
- πͺͺ **Personalised tag-all: every member sees themselves.** New socket method `sock.aunuPersonalTagAll(groupJid, options)`: for EVERY group member the bot sends one card carrying **that member's own profile picture** and their own name, mentioning exactly them β not one generic tag-all message. Pictures come from `profilePictureUrl` (the PN form is used when a member is LID-addressed and the LID store knows the pair); the caption is built from a template with `{name}`, `{number}`, `{mention}`, `{jid}` placeholders; names come from a consumer-supplied `getName` resolver when provided, falling back to the number. Members without a profile picture get a text card, or the `fallbackImage` when set. Built-in anti-spam pacing: a delay between sends (`delayMs`, default 1500) and a member cap (`maxMembers`, default 30); `dm: true` delivers each card to the member's private chat instead. Returns a `{ total, sent, failed, skipped }` summary. Experimental, like the five features of 1.0.47.
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -74,6 +74,27 @@ export function makeLibSignalRepository(auth) {
|
|
|
74
74
|
const addr = jidToSignalProtocolAddress(jid).toString();
|
|
75
75
|
await auth.keys.set({ session: { [addr]: null } });
|
|
76
76
|
},
|
|
77
|
+
async migrateSession(fromJid, toJid) {
|
|
78
|
+
// AunuBaileys: move a stored session record to another address
|
|
79
|
+
// form of the same identity (PN -> LID). The raw record is
|
|
80
|
+
// moved untouched; an existing target record is never
|
|
81
|
+
// overwritten. Returns true when a record was moved.
|
|
82
|
+
const fromAddr = jidToSignalProtocolAddress(fromJid).toString();
|
|
83
|
+
const toAddr = jidToSignalProtocolAddress(toJid).toString();
|
|
84
|
+
if (fromAddr === toAddr) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const { [fromAddr]: record } = await auth.keys.get('session', [fromAddr]);
|
|
88
|
+
if (!record) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const { [toAddr]: existing } = await auth.keys.get('session', [toAddr]);
|
|
92
|
+
if (existing) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
await auth.keys.set({ session: { [toAddr]: record, [fromAddr]: null } });
|
|
96
|
+
return true;
|
|
97
|
+
},
|
|
77
98
|
async injectE2ESession({ jid, session }) {
|
|
78
99
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
79
100
|
await cipher.initOutgoing(session);
|
|
@@ -38,6 +38,39 @@ export interface AunuPersonalTagAllResult {
|
|
|
38
38
|
failed: { jid: string; error: string }[];
|
|
39
39
|
skipped: number;
|
|
40
40
|
}
|
|
41
|
+
export interface AunuCardButton {
|
|
42
|
+
type?: 'reply' | 'url' | 'copy' | 'call';
|
|
43
|
+
displayText?: string;
|
|
44
|
+
text?: string;
|
|
45
|
+
id?: string;
|
|
46
|
+
url?: string;
|
|
47
|
+
copyCode?: string;
|
|
48
|
+
phoneNumber?: string;
|
|
49
|
+
/** Raw native-flow passthrough. */
|
|
50
|
+
name?: string;
|
|
51
|
+
buttonParamsJson?: string | Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
export interface AunuCardOptions {
|
|
54
|
+
title?: string;
|
|
55
|
+
subtitle?: string;
|
|
56
|
+
/** Body text fused under the photo in the same bubble. */
|
|
57
|
+
text?: string;
|
|
58
|
+
footer?: string;
|
|
59
|
+
/** Header photo (Buffer or { url }); uploaded and embedded as the card header β it does not open as a normal photo. */
|
|
60
|
+
image?: Buffer | { url: string };
|
|
61
|
+
/** Prebuilt imageMessage object, used as-is when provided. */
|
|
62
|
+
imageMessage?: Record<string, unknown>;
|
|
63
|
+
buttons?: AunuCardButton[];
|
|
64
|
+
messageOptions?: MiscMessageGenerationOptions;
|
|
65
|
+
}
|
|
66
|
+
export interface AunuFakeQuoteOptions {
|
|
67
|
+
/** JID the fabricated quote pretends to come from. Defaults to the chat JID. */
|
|
68
|
+
from?: string;
|
|
69
|
+
/** Text of the fabricated quoted message. */
|
|
70
|
+
text?: string;
|
|
71
|
+
id?: string;
|
|
72
|
+
quotedMessage?: Record<string, unknown>;
|
|
73
|
+
}
|
|
41
74
|
export interface AunuExperimentalAPI {
|
|
42
75
|
aunuWatermark: (text: string, tag: string) => string;
|
|
43
76
|
aunuReadWatermark: (text: string) => string | null;
|
|
@@ -50,5 +83,11 @@ export interface AunuExperimentalAPI {
|
|
|
50
83
|
aunuCancelSelfDestruct: (messageId: string) => boolean;
|
|
51
84
|
aunuDoctor: () => AunuDoctorReport;
|
|
52
85
|
aunuPersonalTagAll: (groupJid: string, options?: AunuPersonalTagAllOptions) => Promise<AunuPersonalTagAllResult>;
|
|
86
|
+
aunuCard: (jid: string, options?: AunuCardOptions) => Promise<any>;
|
|
87
|
+
aunuFakeQuote: (jid: string, content: Record<string, unknown>, quote?: AunuFakeQuoteOptions, options?: MiscMessageGenerationOptions) => Promise<any>;
|
|
88
|
+
aunuTypewriter: (jid: string, text: string, options?: { steps?: number; intervalMs?: number; messageOptions?: MiscMessageGenerationOptions }) => Promise<any>;
|
|
89
|
+
aunuReactSequence: (jid: string, key: Record<string, unknown>, emojis: string | string[], options?: { intervalMs?: number; messageOptions?: MiscMessageGenerationOptions }) => Promise<number>;
|
|
90
|
+
aunuPostStatus: (text: string, options?: { backgroundColor?: string; font?: number } & MiscMessageGenerationOptions) => Promise<any>;
|
|
91
|
+
aunuPersonalCard: (jid: string | null, targetJid: string, options?: AunuPersonalTagAllOptions) => Promise<any>;
|
|
53
92
|
}
|
|
54
93
|
export declare const attachAunuExperimental: <T>(sock: T) => T & AunuExperimentalAPI;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import baileysVersion from '../Defaults/baileys-version.json' with { type: 'json' };
|
|
2
2
|
import { appendWatermark, computeTypingDuration, extractWatermark, stripWatermark } from '../Utils/aunu-experimental.js';
|
|
3
3
|
import { isLidUser } from '../WABinary/jid-utils.js';
|
|
4
|
+
import { prepareWAMessageMedia } from '../Utils/messages.js';
|
|
5
|
+
import { randomBytes } from 'crypto';
|
|
4
6
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
7
|
/**
|
|
6
8
|
* AunuBaileys EXPERIMENTAL socket features β these exist only in
|
|
@@ -25,6 +27,21 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
25
27
|
* mentioning exactly them β each member sees themselves, not a
|
|
26
28
|
* generic tag-all. Paced sends + a member cap guard against spam
|
|
27
29
|
* limits.
|
|
30
|
+
* 7. Photo card β `aunuCard`: an interactive card whose header photo does
|
|
31
|
+
* NOT open as a normal photo when tapped; a title/name and text sit
|
|
32
|
+
* fused below it in the same bubble, with divider-separated buttons
|
|
33
|
+
* (reply/url/copy/call) underneath.
|
|
34
|
+
* 8. Fabricated quote β `aunuFakeQuote`: send any content carrying a
|
|
35
|
+
* made-up quoted message, as if replying to someone.
|
|
36
|
+
* 9. Typewriter β `aunuTypewriter`: send a message in growing pieces by
|
|
37
|
+
* editing it on an interval until the full text stands.
|
|
38
|
+
* 10. Reaction sequence β `aunuReactSequence`: cycle reactions on one
|
|
39
|
+
* message (an animation effect).
|
|
40
|
+
* 11. Styled status β `aunuPostStatus`: post a text status with a
|
|
41
|
+
* background colour and font in one call.
|
|
42
|
+
* 12. Personal card β `aunuPersonalCard`: the one-person form of
|
|
43
|
+
* aunuPersonalTagAll (own profile picture + name card for one target,
|
|
44
|
+
* into a chat or as a DM).
|
|
28
45
|
*/
|
|
29
46
|
export const attachAunuExperimental = (sock) => {
|
|
30
47
|
const scheduled = new Map();
|
|
@@ -144,6 +161,115 @@ export const attachAunuExperimental = (sock) => {
|
|
|
144
161
|
}
|
|
145
162
|
return results;
|
|
146
163
|
};
|
|
164
|
+
const mapCardButton = (b) => {
|
|
165
|
+
if (!b) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
if (b.name) {
|
|
169
|
+
return { name: b.name, buttonParamsJson: typeof b.buttonParamsJson === 'string' ? b.buttonParamsJson : JSON.stringify(b.buttonParamsJson ?? {}) };
|
|
170
|
+
}
|
|
171
|
+
const display_text = b.displayText || b.text || '';
|
|
172
|
+
switch (b.type) {
|
|
173
|
+
case 'url':
|
|
174
|
+
return { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text, url: b.url || '', merchant_url: b.url || '' }) };
|
|
175
|
+
case 'copy':
|
|
176
|
+
return { name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text, id: b.id || 'copy', copy_code: b.copyCode || '' }) };
|
|
177
|
+
case 'call':
|
|
178
|
+
return { name: 'cta_call', buttonParamsJson: JSON.stringify({ display_text, id: b.phoneNumber || '' }) };
|
|
179
|
+
case 'reply':
|
|
180
|
+
default:
|
|
181
|
+
return { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text, id: b.id || display_text }) };
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
sock.aunuCard = async (jid, options = {}) => {
|
|
185
|
+
let imageMessage = options.imageMessage;
|
|
186
|
+
if (!imageMessage && options.image) {
|
|
187
|
+
const prepared = await prepareWAMessageMedia({ image: options.image }, { upload: sock.waUploadToServer });
|
|
188
|
+
imageMessage = prepared.imageMessage;
|
|
189
|
+
}
|
|
190
|
+
const interactive = {
|
|
191
|
+
header: (options.title || options.subtitle || imageMessage)
|
|
192
|
+
? { title: options.title || '', subtitle: options.subtitle, hasMediaAttachment: !!imageMessage, imageMessage }
|
|
193
|
+
: undefined,
|
|
194
|
+
body: { text: options.text || '' },
|
|
195
|
+
footer: options.footer ? { text: options.footer } : undefined,
|
|
196
|
+
buttons: (options.buttons || []).map(mapCardButton).filter(Boolean)
|
|
197
|
+
};
|
|
198
|
+
return sock.sendMessage(jid, { interactive }, options.messageOptions || {});
|
|
199
|
+
};
|
|
200
|
+
sock.aunuFakeQuote = async (jid, content, quote = {}, options = {}) => {
|
|
201
|
+
const contextInfo = {
|
|
202
|
+
...(content?.contextInfo || {}),
|
|
203
|
+
stanzaId: quote.id || ('AUNU' + randomBytes(6).toString('hex').toUpperCase()),
|
|
204
|
+
participant: quote.from || jid,
|
|
205
|
+
quotedMessage: quote.quotedMessage || { conversation: quote.text || '' }
|
|
206
|
+
};
|
|
207
|
+
return sock.sendMessage(jid, { ...content, contextInfo }, options);
|
|
208
|
+
};
|
|
209
|
+
sock.aunuTypewriter = async (jid, text, options = {}) => {
|
|
210
|
+
const full = String(text ?? '');
|
|
211
|
+
const steps = Math.max(1, options.steps ?? 6);
|
|
212
|
+
const intervalMs = options.intervalMs ?? 700;
|
|
213
|
+
const chunk = Math.max(1, Math.ceil(full.length / steps));
|
|
214
|
+
const sentMsg = await sock.sendMessage(jid, { text: full.slice(0, chunk) }, options.messageOptions || {});
|
|
215
|
+
for (let upto = chunk * 2; upto < full.length + chunk; upto += chunk) {
|
|
216
|
+
if (intervalMs > 0) {
|
|
217
|
+
await delay(intervalMs);
|
|
218
|
+
}
|
|
219
|
+
await sock.sendMessage(jid, { text: full.slice(0, upto), edit: sentMsg.key }, options.messageOptions || {});
|
|
220
|
+
if (upto >= full.length) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return sentMsg;
|
|
225
|
+
};
|
|
226
|
+
sock.aunuReactSequence = async (jid, key, emojis, options = {}) => {
|
|
227
|
+
const intervalMs = options.intervalMs ?? 800;
|
|
228
|
+
const list = Array.isArray(emojis) ? emojis : [emojis];
|
|
229
|
+
let n = 0;
|
|
230
|
+
for (const emoji of list) {
|
|
231
|
+
if (n > 0 && intervalMs > 0) {
|
|
232
|
+
await delay(intervalMs);
|
|
233
|
+
}
|
|
234
|
+
await sock.sendMessage(jid, { react: { text: emoji, key } }, options.messageOptions || {});
|
|
235
|
+
n += 1;
|
|
236
|
+
}
|
|
237
|
+
return n;
|
|
238
|
+
};
|
|
239
|
+
sock.aunuPostStatus = async (text, options = {}) => {
|
|
240
|
+
const { backgroundColor = '#000000', font = 0, ...rest } = options;
|
|
241
|
+
return sock.sendMessage('status@broadcast', { text: String(text ?? '') }, { backgroundColor, font, ...rest });
|
|
242
|
+
};
|
|
243
|
+
sock.aunuPersonalCard = async (jid, targetJid, options = {}) => {
|
|
244
|
+
const pn = isLidUser(targetJid) ? (sock.aunuLid?.getPNForLID?.(targetJid) || targetJid) : targetJid;
|
|
245
|
+
const number = pn.split('@')[0].split(':')[0];
|
|
246
|
+
let name = number;
|
|
247
|
+
if (typeof options.getName === 'function') {
|
|
248
|
+
name = (await options.getName(targetJid)) || number;
|
|
249
|
+
}
|
|
250
|
+
const template = options.text || 'Hai {mention} π';
|
|
251
|
+
let caption = template
|
|
252
|
+
.replaceAll('{name}', name)
|
|
253
|
+
.replaceAll('{number}', number)
|
|
254
|
+
.replaceAll('{mention}', '@' + number)
|
|
255
|
+
.replaceAll('{jid}', targetJid);
|
|
256
|
+
if (!caption.includes('@' + number)) {
|
|
257
|
+
caption += ' @' + number;
|
|
258
|
+
}
|
|
259
|
+
let ppUrl;
|
|
260
|
+
try {
|
|
261
|
+
ppUrl = await sock.profilePictureUrl(pn, 'image');
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
ppUrl = undefined;
|
|
265
|
+
}
|
|
266
|
+
const content = ppUrl
|
|
267
|
+
? { image: { url: ppUrl }, caption, mentions: [targetJid] }
|
|
268
|
+
: options.fallbackImage
|
|
269
|
+
? { image: Buffer.isBuffer(options.fallbackImage) ? options.fallbackImage : { url: options.fallbackImage }, caption, mentions: [targetJid] }
|
|
270
|
+
: { text: caption, mentions: [targetJid] };
|
|
271
|
+
return sock.sendMessage(jid || pn, content, options.messageOptions || {});
|
|
272
|
+
};
|
|
147
273
|
sock.aunuDoctor = () => ({
|
|
148
274
|
experimental: true,
|
|
149
275
|
bundledWaVersion: Array.isArray(baileysVersion.version) ? baileysVersion.version.join('.') : null,
|
package/lib/Socket/index.js
CHANGED
|
@@ -27,6 +27,45 @@ const makeWASocket = (config) => {
|
|
|
27
27
|
catch {
|
|
28
28
|
// identity learning must never break message handling
|
|
29
29
|
}
|
|
30
|
+
// AunuBaileys: when live traffic teaches us a PN <-> LID pair, move
|
|
31
|
+
// any stored PN session onto the LID address (best-effort; the
|
|
32
|
+
// decrypt heals remain the fallback).
|
|
33
|
+
try {
|
|
34
|
+
for (const msg of upsert?.messages ?? []) {
|
|
35
|
+
const key = msg?.key ?? {};
|
|
36
|
+
const pairs = [];
|
|
37
|
+
if (key.senderPn && key.senderLid) {
|
|
38
|
+
pairs.push([key.senderPn, key.senderLid]);
|
|
39
|
+
}
|
|
40
|
+
if (key.participantPn && key.participantLid) {
|
|
41
|
+
pairs.push([key.participantPn, key.participantLid]);
|
|
42
|
+
}
|
|
43
|
+
if (key.remoteJid && key.senderLid && !key.fromMe) {
|
|
44
|
+
pairs.push([key.remoteJid, key.senderLid]);
|
|
45
|
+
}
|
|
46
|
+
for (const [pn, lid] of pairs) {
|
|
47
|
+
sock.signalRepository?.migrateSession?.(pn, lid)?.catch?.(() => { });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// session migration must never break message handling
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
sock.ev.on('connection.update', (update) => {
|
|
56
|
+
// AunuBaileys: migrate the account's OWN session to its LID
|
|
57
|
+
// address once the connection opens with both identities known.
|
|
58
|
+
try {
|
|
59
|
+
if (update.connection === 'open') {
|
|
60
|
+
const me = sock.authState?.creds?.me;
|
|
61
|
+
if (me?.id && me?.lid) {
|
|
62
|
+
sock.signalRepository?.migrateSession?.(me.id, me.lid)?.catch?.(() => { });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// session migration must never break connection handling
|
|
68
|
+
}
|
|
30
69
|
});
|
|
31
70
|
return sock;
|
|
32
71
|
};
|
package/lib/Types/Signal.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export type SignalRepository = {
|
|
|
54
54
|
injectE2ESession(opts: E2ESessionOpts): Promise<void>;
|
|
55
55
|
/** AunuBaileys: delete the stored E2E session for a JID (used by the Bad MAC self-heal). */
|
|
56
56
|
deleteSession(jid: string): Promise<void>;
|
|
57
|
+
migrateSession(fromJid: string, toJid: string): Promise<boolean>;
|
|
57
58
|
/** AunuBaileys: delete the stored sender-key record for a group author (stale group session heal). */
|
|
58
59
|
deleteSenderKey(group: string, authorJid: string): Promise<void>;
|
|
59
60
|
jidToSignalProtocolAddress(jid: string): string;
|
package/lib/Utils/auth-utils.js
CHANGED
|
@@ -143,19 +143,32 @@ export const addTransactionCapability = (state, logger, { maxCommitRetries, dela
|
|
|
143
143
|
// retry mechanism to ensure we've some recovery
|
|
144
144
|
// in case a transaction fails in the first attempt
|
|
145
145
|
let tries = maxCommitRetries;
|
|
146
|
+
let committed = false;
|
|
147
|
+
let lastCommitError;
|
|
146
148
|
while (tries) {
|
|
147
149
|
tries -= 1;
|
|
148
150
|
//eslint-disable-next-line max-depth
|
|
149
151
|
try {
|
|
150
152
|
await state.set(mutations);
|
|
151
153
|
logger.trace({ dbQueriesInTransaction }, 'committed transaction');
|
|
154
|
+
committed = true;
|
|
152
155
|
break;
|
|
153
156
|
}
|
|
154
157
|
catch (error) {
|
|
158
|
+
lastCommitError = error;
|
|
155
159
|
logger.warn(`failed to commit ${Object.keys(mutations).length} mutations, tries left=${tries}`);
|
|
156
160
|
await delay(delayBetweenTriesMs);
|
|
157
161
|
}
|
|
158
162
|
}
|
|
163
|
+
if (!committed) {
|
|
164
|
+
// AunuBaileys: a commit that fails through every retry
|
|
165
|
+
// must NOT be swallowed β the in-memory ratchet has
|
|
166
|
+
// advanced while the persisted state has not, and
|
|
167
|
+
// every later message would fail against the stale
|
|
168
|
+
// record. Throw so the caller learns its state was
|
|
169
|
+
// never persisted.
|
|
170
|
+
throw lastCommitError ?? new Error('failed to commit transaction mutations');
|
|
171
|
+
}
|
|
159
172
|
}
|
|
160
173
|
else {
|
|
161
174
|
logger.trace('no mutations in transaction');
|
package/lib/Utils/signal.js
CHANGED
|
@@ -135,6 +135,7 @@ export const extractDeviceJids = (result, myJid, excludeZeroDevices) => {
|
|
|
135
135
|
for (const { id: device, keyIndex } of deviceList) {
|
|
136
136
|
if ((!excludeZeroDevices || device !== 0) && // if zero devices are not-excluded, or device is non zero
|
|
137
137
|
(myUser !== user || myDevice !== device) && // either different user or if me user, not this device
|
|
138
|
+
device !== 99 && // AunuBaileys: hosted / Cloud-API companion devices (:99) are not E2E targets β libsignal rejects them ("Unexpected non-hosted device JID with device 99"); skip them when building the device list
|
|
138
139
|
(device === 0 || !!keyIndex) // ensure that "key-index" is specified for "non-zero" devices, produces a bad req otherwise
|
|
139
140
|
) {
|
|
140
141
|
extracted.push({ user, device });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aunubaileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.51",
|
|
5
5
|
"description": "AunuBaileys \u2014 a WhatsApp Web API for bots that never sleep. Full upstream power with the beloved in-memory store restored and pairing that just works. Forged by AunuCore.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|