aunubaileys 1.0.51 β 1.0.53
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 +10 -2
- package/lib/Socket/aunu-experimental.d.ts +27 -0
- package/lib/Socket/aunu-experimental.js +145 -2
- package/lib/Utils/aunu-experimental.js +30 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
[](https://www.npmjs.com/package/aunubaileys)
|
|
9
9
|
[](https://github.com/WhiskeySockets/Baileys)
|
|
10
10
|
[](./LICENSE)
|
|
11
|
-
[](https://github.com/AunuCore/AunuBaileys-lib/stargazers)
|
|
12
|
+
[](https://github.com/AunuCore/AunuBaileys-lib/forks)
|
|
13
13
|
|
|
14
14
|
**Full upstream power β with the soul that community forks used to have.**
|
|
15
15
|
The in-memory store is back, legacy exports are back, and every upstream update flows straight in.
|
|
@@ -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.53 / Baru di 1.0.53 β EXPERIMENTAL
|
|
68
|
+
|
|
69
|
+
- π **Five more experimental features (17 total).** **`aunuSideText`** β text with a small picture **at the side**: a name/title beside the picture and the chat under the name (the preview layout group menus use); the picture can be someone's real profile picture (`profileOf`), your own image, the built-in grey **"deleted account"** avatar (`deletedProfile: true`), or no picture at all. **`aunuGhostMention`** β mention every group member invisibly: everyone is notified, the text shows no @ pile-up. **`aunuFakeForward`** β the forwarded look (high forwarding score, optional channel attribution). **`aunuCountdown`** β one message edited down a countdown to a final text. **`aunuSplitText`** β a long text sent as a self-quoting chain. New exported utils: `getDeletedProfileImage()` (the embedded deleted-account avatar PNG) and `buildSideTextAdReply()`.
|
|
70
|
+
|
|
71
|
+
### π§ͺ What's new in 1.0.52 / Baru di 1.0.52 β EXPERIMENTAL
|
|
72
|
+
|
|
73
|
+
- π **`aunuCard` gains like/dislike buttons.** The new `likeDislike: true` option appends two quick-reply buttons under the card β **π Suka** (id `aunu_like`) and **π Tidak Suka** (id `aunu_dislike`) β after any custom buttons. The ids are overridable via `likeId`/`dislikeId`; taps return to the bot as button replies carrying those ids, so votes can be counted. Without the option, card behaviour is exactly as in 1.0.50.
|
|
74
|
+
|
|
67
75
|
### π©Ή What's new in 1.0.51 / Baru di 1.0.51
|
|
68
76
|
|
|
69
77
|
- π **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.
|
|
@@ -61,6 +61,10 @@ export interface AunuCardOptions {
|
|
|
61
61
|
/** Prebuilt imageMessage object, used as-is when provided. */
|
|
62
62
|
imageMessage?: Record<string, unknown>;
|
|
63
63
|
buttons?: AunuCardButton[];
|
|
64
|
+
/** Append π Suka / π Tidak Suka quick-reply buttons under the card. Taps return as button replies with the like/dislike ids. */
|
|
65
|
+
likeDislike?: boolean;
|
|
66
|
+
likeId?: string;
|
|
67
|
+
dislikeId?: string;
|
|
64
68
|
messageOptions?: MiscMessageGenerationOptions;
|
|
65
69
|
}
|
|
66
70
|
export interface AunuFakeQuoteOptions {
|
|
@@ -71,6 +75,24 @@ export interface AunuFakeQuoteOptions {
|
|
|
71
75
|
id?: string;
|
|
72
76
|
quotedMessage?: Record<string, unknown>;
|
|
73
77
|
}
|
|
78
|
+
export interface AunuSideTextOptions {
|
|
79
|
+
/** The chat text (required). */
|
|
80
|
+
text: string;
|
|
81
|
+
/** Name/title beside the picture. `name` is an alias. */
|
|
82
|
+
title?: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
/** Line under the title; defaults to the text itself. */
|
|
85
|
+
body?: string;
|
|
86
|
+
/** Side picture as raw bytes... */
|
|
87
|
+
image?: Buffer | { url: string };
|
|
88
|
+
/** ...or fetch this JID's real profile picture... */
|
|
89
|
+
profileOf?: string;
|
|
90
|
+
/** ...or use the built-in "deleted account" grey avatar... */
|
|
91
|
+
deletedProfile?: boolean;
|
|
92
|
+
/** Optional link opened when the preview block is tapped. Never substituted when omitted. */
|
|
93
|
+
url?: string;
|
|
94
|
+
messageOptions?: MiscMessageGenerationOptions;
|
|
95
|
+
}
|
|
74
96
|
export interface AunuExperimentalAPI {
|
|
75
97
|
aunuWatermark: (text: string, tag: string) => string;
|
|
76
98
|
aunuReadWatermark: (text: string) => string | null;
|
|
@@ -89,5 +111,10 @@ export interface AunuExperimentalAPI {
|
|
|
89
111
|
aunuReactSequence: (jid: string, key: Record<string, unknown>, emojis: string | string[], options?: { intervalMs?: number; messageOptions?: MiscMessageGenerationOptions }) => Promise<number>;
|
|
90
112
|
aunuPostStatus: (text: string, options?: { backgroundColor?: string; font?: number } & MiscMessageGenerationOptions) => Promise<any>;
|
|
91
113
|
aunuPersonalCard: (jid: string | null, targetJid: string, options?: AunuPersonalTagAllOptions) => Promise<any>;
|
|
114
|
+
aunuSideText: (jid: string, options: AunuSideTextOptions) => Promise<any>;
|
|
115
|
+
aunuGhostMention: (jid: string, content: Record<string, unknown>, options?: MiscMessageGenerationOptions) => Promise<any>;
|
|
116
|
+
aunuFakeForward: (jid: string, content: Record<string, unknown>, options?: { score?: number; channelName?: string; channelJid?: string; serverMessageId?: number; messageOptions?: MiscMessageGenerationOptions }) => Promise<any>;
|
|
117
|
+
aunuCountdown: (jid: string, options?: { from?: number; intervalMs?: number; format?: (n: number) => string; finalText?: string; messageOptions?: MiscMessageGenerationOptions }) => Promise<any>;
|
|
118
|
+
aunuSplitText: (jid: string, text: string, options?: { maxChars?: number; messageOptions?: MiscMessageGenerationOptions }) => Promise<any[]>;
|
|
92
119
|
}
|
|
93
120
|
export declare const attachAunuExperimental: <T>(sock: T) => T & AunuExperimentalAPI;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import baileysVersion from '../Defaults/baileys-version.json' with { type: 'json' };
|
|
2
|
-
import { appendWatermark, computeTypingDuration, extractWatermark, stripWatermark } from '../Utils/aunu-experimental.js';
|
|
2
|
+
import { appendWatermark, buildSideTextAdReply, computeTypingDuration, encodeWatermark, extractWatermark, getDeletedProfileImage, stripWatermark } from '../Utils/aunu-experimental.js';
|
|
3
3
|
import { isLidUser } from '../WABinary/jid-utils.js';
|
|
4
4
|
import { prepareWAMessageMedia } from '../Utils/messages.js';
|
|
5
5
|
import { randomBytes } from 'crypto';
|
|
@@ -42,6 +42,18 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
42
42
|
* 12. Personal card β `aunuPersonalCard`: the one-person form of
|
|
43
43
|
* aunuPersonalTagAll (own profile picture + name card for one target,
|
|
44
44
|
* into a chat or as a DM).
|
|
45
|
+
* 13. Side-profile text β `aunuSideText`: text with a small picture at
|
|
46
|
+
* the side, a name beside it and the chat under the name; the
|
|
47
|
+
* picture can be a real profile picture, the built-in "deleted
|
|
48
|
+
* account" avatar, or absent entirely.
|
|
49
|
+
* 14. Ghost mention β `aunuGhostMention`: mention every group member
|
|
50
|
+
* invisibly (notifications fire, no @ text shows).
|
|
51
|
+
* 15. Fake forward β `aunuFakeForward`: the forwarded look with a high
|
|
52
|
+
* score and optional channel attribution.
|
|
53
|
+
* 16. Countdown β `aunuCountdown`: one message edited down a countdown
|
|
54
|
+
* to a final text.
|
|
55
|
+
* 17. Split text β `aunuSplitText`: a long text as a self-quoting
|
|
56
|
+
* chain of messages.
|
|
45
57
|
*/
|
|
46
58
|
export const attachAunuExperimental = (sock) => {
|
|
47
59
|
const scheduled = new Map();
|
|
@@ -187,13 +199,18 @@ export const attachAunuExperimental = (sock) => {
|
|
|
187
199
|
const prepared = await prepareWAMessageMedia({ image: options.image }, { upload: sock.waUploadToServer });
|
|
188
200
|
imageMessage = prepared.imageMessage;
|
|
189
201
|
}
|
|
202
|
+
const cardButtons = (options.buttons || []).map(mapCardButton).filter(Boolean);
|
|
203
|
+
if (options.likeDislike) {
|
|
204
|
+
cardButtons.push({ name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'π Suka', id: options.likeId || 'aunu_like' }) });
|
|
205
|
+
cardButtons.push({ name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'π Tidak Suka', id: options.dislikeId || 'aunu_dislike' }) });
|
|
206
|
+
}
|
|
190
207
|
const interactive = {
|
|
191
208
|
header: (options.title || options.subtitle || imageMessage)
|
|
192
209
|
? { title: options.title || '', subtitle: options.subtitle, hasMediaAttachment: !!imageMessage, imageMessage }
|
|
193
210
|
: undefined,
|
|
194
211
|
body: { text: options.text || '' },
|
|
195
212
|
footer: options.footer ? { text: options.footer } : undefined,
|
|
196
|
-
buttons:
|
|
213
|
+
buttons: cardButtons
|
|
197
214
|
};
|
|
198
215
|
return sock.sendMessage(jid, { interactive }, options.messageOptions || {});
|
|
199
216
|
};
|
|
@@ -281,6 +298,132 @@ export const attachAunuExperimental = (sock) => {
|
|
|
281
298
|
selfDestructPending: destructs.size,
|
|
282
299
|
generatedAt: new Date().toISOString(),
|
|
283
300
|
});
|
|
301
|
+
/**
|
|
302
|
+
* EXPERIMENTAL (1.0.53): side-profile text. Sends a text message whose
|
|
303
|
+
* preview block shows a small picture AT THE SIDE, a name/title next
|
|
304
|
+
* to it, and the chat text under the name β the layout group menus
|
|
305
|
+
* use. Picture variants: `image` (Buffer or { url }), `profileOf`
|
|
306
|
+
* (a JID whose real profile picture is fetched), `deletedProfile:
|
|
307
|
+
* true` (the built-in grey "deleted account" avatar), or no picture
|
|
308
|
+
* at all. Client rendering of the preview is version-dependent.
|
|
309
|
+
*/
|
|
310
|
+
sock.aunuSideText = async (jid, options = {}) => {
|
|
311
|
+
const { text, title, name, body, url, messageOptions } = options;
|
|
312
|
+
if (!text)
|
|
313
|
+
throw new Error('aunuSideText: options.text is required');
|
|
314
|
+
let thumbnail = null;
|
|
315
|
+
if (options.deletedProfile)
|
|
316
|
+
thumbnail = getDeletedProfileImage();
|
|
317
|
+
else if (Buffer.isBuffer(options.image))
|
|
318
|
+
thumbnail = options.image;
|
|
319
|
+
else if (options.profileOf) {
|
|
320
|
+
try {
|
|
321
|
+
const ppUrl = await sock.profilePictureUrl(options.profileOf, 'image');
|
|
322
|
+
if (ppUrl)
|
|
323
|
+
thumbnail = Buffer.from(await (await fetch(ppUrl)).arrayBuffer());
|
|
324
|
+
}
|
|
325
|
+
catch { /* no picture β the text simply goes without one */ }
|
|
326
|
+
}
|
|
327
|
+
else if (options.image?.url)
|
|
328
|
+
thumbnail = Buffer.from(await (await fetch(options.image.url)).arrayBuffer());
|
|
329
|
+
const externalAdReply = buildSideTextAdReply({ title: title ?? name ?? '', body: body ?? text, thumbnail, url });
|
|
330
|
+
return sock.sendMessage(jid, { text, contextInfo: { externalAdReply } }, messageOptions);
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* EXPERIMENTAL (1.0.53): ghost mention β mention EVERY group member
|
|
334
|
+
* in the message's mention list without any visible @ text, so all
|
|
335
|
+
* members are notified while the text stays clean.
|
|
336
|
+
*/
|
|
337
|
+
sock.aunuGhostMention = async (jid, content, options = {}) => {
|
|
338
|
+
if (!String(jid).endsWith('@g.us'))
|
|
339
|
+
throw new Error('aunuGhostMention: jid must be a group JID');
|
|
340
|
+
const metadata = await sock.groupMetadata(jid);
|
|
341
|
+
const ids = (metadata?.participants || []).map((p) => p.id).filter(Boolean);
|
|
342
|
+
const mentions = [...new Set([...(content?.mentions || []), ...ids])];
|
|
343
|
+
return sock.sendMessage(jid, { ...content, mentions }, options);
|
|
344
|
+
};
|
|
345
|
+
/**
|
|
346
|
+
* EXPERIMENTAL (1.0.53): fake forward β the message carries the
|
|
347
|
+
* forwarded look: `isForwarded` with a high forwarding score, and
|
|
348
|
+
* optionally a channel attribution line (name + JID).
|
|
349
|
+
*/
|
|
350
|
+
sock.aunuFakeForward = async (jid, content, options = {}) => {
|
|
351
|
+
const contextInfo = {
|
|
352
|
+
...(content?.contextInfo || {}),
|
|
353
|
+
isForwarded: true,
|
|
354
|
+
forwardingScore: options.score ?? 999,
|
|
355
|
+
};
|
|
356
|
+
if (options.channelName) {
|
|
357
|
+
contextInfo.forwardedNewsletterMessageInfo = {
|
|
358
|
+
newsletterJid: options.channelJid ?? '120363000000000000@newsletter',
|
|
359
|
+
newsletterName: options.channelName,
|
|
360
|
+
contentType: 1,
|
|
361
|
+
serverMessageId: options.serverMessageId ?? 1,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return sock.sendMessage(jid, { ...content, contextInfo }, options.messageOptions);
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* EXPERIMENTAL (1.0.53): countdown β send one message, then edit it
|
|
368
|
+
* down from `from` to 0 on an interval, finishing with `finalText`.
|
|
369
|
+
*/
|
|
370
|
+
sock.aunuCountdown = async (jid, options = {}) => {
|
|
371
|
+
const from = options.from ?? 5;
|
|
372
|
+
const intervalMs = options.intervalMs ?? 1000;
|
|
373
|
+
const format = options.format ?? ((n) => `\u23F3 ${n}`);
|
|
374
|
+
let msg = await sock.sendMessage(jid, { text: format(from) }, options.messageOptions);
|
|
375
|
+
const key = msg.key;
|
|
376
|
+
for (let n = from - 1; n >= 0; n--) {
|
|
377
|
+
await delay(intervalMs);
|
|
378
|
+
msg = await sock.sendMessage(jid, { text: format(n), edit: key }, options.messageOptions);
|
|
379
|
+
}
|
|
380
|
+
if (options.finalText != null) {
|
|
381
|
+
await delay(intervalMs);
|
|
382
|
+
msg = await sock.sendMessage(jid, { text: options.finalText, edit: key }, options.messageOptions);
|
|
383
|
+
}
|
|
384
|
+
return msg;
|
|
385
|
+
};
|
|
386
|
+
/**
|
|
387
|
+
* EXPERIMENTAL (1.0.53): split text β a long text is sent as a chain
|
|
388
|
+
* of messages, each quoting the previous one, split on paragraph
|
|
389
|
+
* boundaries where possible.
|
|
390
|
+
*/
|
|
391
|
+
sock.aunuSplitText = async (jid, text, options = {}) => {
|
|
392
|
+
const maxChars = options.maxChars ?? 1000;
|
|
393
|
+
const chunks = [];
|
|
394
|
+
let current = '';
|
|
395
|
+
for (const para of String(text).split(/\n\n+/)) {
|
|
396
|
+
const pieces = [];
|
|
397
|
+
let rest = para;
|
|
398
|
+
while (rest.length > maxChars) {
|
|
399
|
+
let cut = rest.lastIndexOf(' ', maxChars);
|
|
400
|
+
if (cut < maxChars * 0.5)
|
|
401
|
+
cut = maxChars;
|
|
402
|
+
pieces.push(rest.slice(0, cut));
|
|
403
|
+
rest = rest.slice(cut).trimStart();
|
|
404
|
+
}
|
|
405
|
+
if (rest)
|
|
406
|
+
pieces.push(rest);
|
|
407
|
+
for (const piece of pieces) {
|
|
408
|
+
if (current && (current.length + 2 + piece.length) > maxChars) {
|
|
409
|
+
chunks.push(current);
|
|
410
|
+
current = piece;
|
|
411
|
+
}
|
|
412
|
+
else
|
|
413
|
+
current = current ? current + '\n\n' + piece : piece;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (current)
|
|
417
|
+
chunks.push(current);
|
|
418
|
+
const sent = [];
|
|
419
|
+
let prev;
|
|
420
|
+
for (const chunk of chunks) {
|
|
421
|
+
const msg = await sock.sendMessage(jid, { text: chunk }, prev ? { ...options.messageOptions, quoted: prev } : options.messageOptions);
|
|
422
|
+
sent.push(msg);
|
|
423
|
+
prev = msg;
|
|
424
|
+
}
|
|
425
|
+
return sent;
|
|
426
|
+
};
|
|
284
427
|
return sock;
|
|
285
428
|
};
|
|
286
429
|
//# sourceMappingURL=aunu-experimental.js.map
|
|
@@ -17,6 +17,36 @@ const textDecoder = new TextDecoder();
|
|
|
17
17
|
* Encode a short string as an invisible zero-width sequence. Returns an
|
|
18
18
|
* empty string for an empty payload.
|
|
19
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* EXPERIMENTAL (AunuBaileys-only): a small embedded PNG of the WhatsApp
|
|
22
|
+
* "deleted account" avatar β a grey silhouette on light grey, drawn
|
|
23
|
+
* programmatically (96x96, 375 bytes). Used by `aunuSideText` for the
|
|
24
|
+
* deleted-profile side picture; exported so bots can reuse the look.
|
|
25
|
+
*/
|
|
26
|
+
export const DELETED_PROFILE_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAABPklEQVR4nO3aTWpCQRCFUVfvTHB1mSSLcZiAoETr56oHvgVUH3ryut7h6/tHNzqsTxAeIECAAAEKDhAgQIAABQcIECBAgIIDBAgQIEB/Op7O6zNkAR1P59t9LtBdmgSmHaB/0ewyLQA9rLNiNA30pM680ShQic6wEaAYoEKdSSNAGUDlOmNGgAABAvTuQE06M0ZuECBAgAAB8i0GKMxobGZASUDepCeMhqe1F4sEeoBpa0i7+Xiga6/1GaKB0gIECBAgQMEBAgQIEKDgAAEC9FlAnjt+IfLfW201koBKaOaZ/GG2CtRKM8PUCDSm02rUBTSs02fUArSi02RUD7So02FUDLSuU25UCbTu0mFUBrQu0mQEaARo3aLPCBCgdaB1hVYjQIAAAXploPXzdxu5QYAAAQL03kDJRs8fDdCdLjutlqODlBNDAAAAAElFTkSuQmCC';
|
|
27
|
+
export const getDeletedProfileImage = () => Buffer.from(DELETED_PROFILE_PNG_BASE64, 'base64');
|
|
28
|
+
/**
|
|
29
|
+
* EXPERIMENTAL: build the `externalAdReply` object behind `aunuSideText` β
|
|
30
|
+
* a preview block with the picture at the side, the title where a name
|
|
31
|
+
* sits, and the body text under the title. URLs are strictly
|
|
32
|
+
* caller-supplied; nothing is ever substituted.
|
|
33
|
+
*/
|
|
34
|
+
export const buildSideTextAdReply = ({ title, body, thumbnail, url } = {}) => {
|
|
35
|
+
const ad = {
|
|
36
|
+
title: title ?? '',
|
|
37
|
+
body: body ?? '',
|
|
38
|
+
mediaType: thumbnail ? 1 : 0,
|
|
39
|
+
renderLargerThumbnail: false,
|
|
40
|
+
showAdAttribution: false,
|
|
41
|
+
};
|
|
42
|
+
if (thumbnail)
|
|
43
|
+
ad.thumbnail = thumbnail;
|
|
44
|
+
if (url) {
|
|
45
|
+
ad.mediaUrl = url;
|
|
46
|
+
ad.sourceUrl = url;
|
|
47
|
+
}
|
|
48
|
+
return ad;
|
|
49
|
+
};
|
|
20
50
|
export const encodeWatermark = (payload) => {
|
|
21
51
|
if (!payload) {
|
|
22
52
|
return '';
|
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.53",
|
|
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",
|