aunubaileys 1.0.1 → 1.0.3
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 +18 -0
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.js +22 -2
- package/lib/Socket/Client/websocket.js +3 -0
- package/lib/Socket/index.js +4 -1
- package/lib/Socket/messages-send.js +52 -4
- package/lib/Socket/newsletter.js +8 -0
- package/lib/Socket/socket.js +41 -2
- package/lib/Types/Message.d.ts +32 -1
- package/lib/Types/Newsletter.js +4 -0
- package/lib/Utils/aunu-handler.d.ts +11 -0
- package/lib/Utils/aunu-handler.js +27 -0
- package/lib/Utils/messages-media.d.ts +2 -1
- package/lib/Utils/messages-media.js +11 -4
- package/lib/Utils/messages.js +296 -1
- package/lib/Utils/use-multi-file-auth-state.js +5 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -58,6 +58,24 @@ sock.ev.on('creds.update', saveCreds)
|
|
|
58
58
|
|
|
59
59
|
Everything else is pure upstream. When upstream moves, we rebase the patch layer — that discipline is the whole point of this fork.
|
|
60
60
|
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### 🆕 What's new in 1.0.3 / Baru di 1.0.3
|
|
64
|
+
|
|
65
|
+
- ⚡ **Modern core** — latest WA version `2.3000.1035194821`, 812 pre-keys, tuned WebSocket (no per-message deflate, 100 MB payload).
|
|
66
|
+
- 🧩 **More message types** — quiz polls (newsletter), poll result snapshots, poll updates, payment invites, order messages.
|
|
67
|
+
- 🛠️ **Developer API** — `sock.aunuHandler` (send/reply/react helpers), `fetchAccountReachoutTimelock()`, `fetchNewChatMessageCap()`, `registerSocketEndHandler()`, `newsletterId()` helper.
|
|
68
|
+
|
|
69
|
+
### 🆕 What's new in 1.0.2 / Baru di 1.0.2
|
|
70
|
+
|
|
71
|
+
- 📦 **Sticker packs** — send full sticker packs with `stickerPack` (cover + up to 60 stickers).
|
|
72
|
+
- 🖼️ **Album messages** — send grouped photos/videos with `album`.
|
|
73
|
+
- 📣 **Newsletter media fixed** — media uploads to channels use the proper newsletter paths.
|
|
74
|
+
- 🤖 **AI label** — mark bot replies with `ai: true` in private chats.
|
|
75
|
+
- 🔐 **Sturdier connections & sessions** — pre-key upload timeout + atomic session file writes.
|
|
76
|
+
|
|
77
|
+
**Credits:** features adapted from the community — [@itsliaaa/baileys](https://www.npmjs.com/package/@itsliaaa/baileys) (sticker pack, album, newsletter media, AI label, atomic auth writes), [MichelleBot/baileys](https://github.com/MichelleBot/baileys) (connection fix), [neoxr/baileys](https://github.com/neoxr/baileys) (sticker pack) — merged into AunuBaileys with gratitude. 🙏
|
|
78
|
+
|
|
61
79
|
---
|
|
62
80
|
|
|
63
81
|
## 🇮🇩 Bahasa Indonesia
|
package/lib/Defaults/index.js
CHANGED
|
@@ -64,6 +64,8 @@ export const MEDIA_PATH_MAP = {
|
|
|
64
64
|
document: '/mms/document',
|
|
65
65
|
audio: '/mms/audio',
|
|
66
66
|
sticker: '/mms/image',
|
|
67
|
+
'sticker-pack': '/mms/sticker-pack',
|
|
68
|
+
'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack',
|
|
67
69
|
'thumbnail-link': '/mms/image',
|
|
68
70
|
'product-catalog-image': '/product/image',
|
|
69
71
|
'md-app-state': '',
|
|
@@ -91,11 +93,29 @@ export const MEDIA_HKDF_KEY_MAPPING = {
|
|
|
91
93
|
};
|
|
92
94
|
export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
|
|
93
95
|
export const MIN_PREKEY_COUNT = 5;
|
|
94
|
-
export const INITIAL_PREKEY_COUNT =
|
|
96
|
+
export const INITIAL_PREKEY_COUNT = 812;
|
|
95
97
|
export const DEFAULT_CACHE_TTLS = {
|
|
96
98
|
SIGNAL_STORE: 5 * 60, // 5 minutes
|
|
97
99
|
MSG_RETRY: 60 * 60, // 1 hour
|
|
98
100
|
CALL_OFFER: 5 * 60, // 5 minutes
|
|
99
101
|
USER_DEVICES: 5 * 60 // 5 minutes
|
|
100
102
|
};
|
|
101
|
-
//# sourceMappingURL=index.js.map
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
104
|
+
// AunuBaileys: peta path upload khusus newsletter (dari @itsliaaa/baileys)
|
|
105
|
+
export const NEWSLETTER_MEDIA_PATH_MAP = {
|
|
106
|
+
image: '/newsletter/newsletter-image',
|
|
107
|
+
video: '/newsletter/newsletter-video',
|
|
108
|
+
audio: '/newsletter/newsletter-audio',
|
|
109
|
+
document: '/newsletter/newsletter-document',
|
|
110
|
+
sticker: '/newsletter/newsletter-sticker',
|
|
111
|
+
gif: '/newsletter/newsletter-gif',
|
|
112
|
+
ptt: '/newsletter/newsletter-ptt',
|
|
113
|
+
ptv: '/newsletter/newsletter-ptv',
|
|
114
|
+
'music-artwork': '/mms/newsletter-music-artwork',
|
|
115
|
+
'sticker-pack': '/newsletter/newsletter-sticker-pack',
|
|
116
|
+
'thumbnail-link': '/newsletter/newsletter-thumbnail-link',
|
|
117
|
+
'waffle-image': '/mms/waffle-image',
|
|
118
|
+
'waffle-video': '/mms/waffle-video'
|
|
119
|
+
};
|
|
120
|
+
// AunuBaileys: payload label AI (dari @itsliaaa/baileys)
|
|
121
|
+
export const BIZ_BOT_SUPPORT_PAYLOAD = '{"version":1,"is_ai_message":true,"should_upload_client_logs":false,"should_show_system_message":false,"ticket_id":"7004947587700716","citation_items":[],"ticket_locale":"us"}';
|
|
@@ -23,6 +23,9 @@ export class WebSocketClient extends AbstractSocketClient {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
this.socket = new WebSocket(this.url, {
|
|
26
|
+
// AunuBaileys: stabilitas WS — tanpa kompresi per-message, payload besar aman
|
|
27
|
+
perMessageDeflate: false,
|
|
28
|
+
maxPayload: 100 * 1024 * 1024,
|
|
26
29
|
origin: DEFAULT_ORIGIN,
|
|
27
30
|
headers: this.config.options?.headers,
|
|
28
31
|
handshakeTimeout: this.config.connectTimeoutMs,
|
package/lib/Socket/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
|
|
2
2
|
import { makeCommunitiesSocket } from './communities.js';
|
|
3
|
+
import { AunuHandler } from '../Utils/aunu-handler.js';
|
|
3
4
|
// export the last socket layer
|
|
4
5
|
const makeWASocket = (config) => {
|
|
5
6
|
const newConfig = {
|
|
@@ -11,7 +12,9 @@ const makeWASocket = (config) => {
|
|
|
11
12
|
if (config.shouldSyncHistoryMessage === undefined) {
|
|
12
13
|
newConfig.shouldSyncHistoryMessage = () => !!newConfig.syncFullHistory;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
const sock = makeCommunitiesSocket(newConfig);
|
|
16
|
+
sock.aunuHandler = new AunuHandler(sock);
|
|
17
|
+
return sock;
|
|
15
18
|
};
|
|
16
19
|
export default makeWASocket;
|
|
17
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import NodeCache from '@cacheable/node-cache';
|
|
2
2
|
import { Boom } from '@hapi/boom';
|
|
3
3
|
import { proto } from '../../WAProto/index.js';
|
|
4
|
-
import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
4
|
+
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
5
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, delay, extractDeviceJids, generateMessageIDV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
6
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
7
|
-
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
7
|
+
import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidNewsletter, isJidUser, isLidUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
8
8
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
9
9
|
import { makeGroupsSocket } from './groups.js';
|
|
10
10
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
@@ -654,7 +654,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
654
654
|
}),
|
|
655
655
|
//TODO: CACHE
|
|
656
656
|
getProfilePicUrl: sock.profilePictureUrl,
|
|
657
|
-
upload: waUploadToServer,
|
|
657
|
+
upload: (fp, opts) => waUploadToServer(fp, { ...opts, newsletter: isJidNewsletter(jid) }),
|
|
658
658
|
mediaCache: config.mediaCache,
|
|
659
659
|
options: config.options,
|
|
660
660
|
messageId: generateMessageIDV2(sock.user?.id),
|
|
@@ -664,6 +664,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
664
664
|
const isEditMsg = 'edit' in content && !!content.edit;
|
|
665
665
|
const isPinMsg = 'pin' in content && !!content.pin;
|
|
666
666
|
const isPollMessage = 'poll' in content && !!content.poll;
|
|
667
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
667
668
|
const additionalAttributes = {};
|
|
668
669
|
const additionalNodes = [];
|
|
669
670
|
// required for delete
|
|
@@ -690,6 +691,21 @@ export const makeMessagesSocket = (config) => {
|
|
|
690
691
|
}
|
|
691
692
|
});
|
|
692
693
|
}
|
|
694
|
+
// AunuBaileys: label AI (dari @itsliaaa/baileys) — hanya chat pribadi
|
|
695
|
+
else if (isAiMsg) {
|
|
696
|
+
if (!(isJidUser(jid) || isLidUser(jid))) {
|
|
697
|
+
throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
|
|
698
|
+
}
|
|
699
|
+
if (fullMsg.message.messageContextInfo) {
|
|
700
|
+
fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
|
|
701
|
+
}
|
|
702
|
+
additionalNodes.push({
|
|
703
|
+
tag: 'bot',
|
|
704
|
+
attrs: { biz_bot: '1' },
|
|
705
|
+
content: undefined
|
|
706
|
+
});
|
|
707
|
+
delete content.ai;
|
|
708
|
+
}
|
|
693
709
|
if ('cachedGroupMetadata' in options) {
|
|
694
710
|
console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.');
|
|
695
711
|
}
|
|
@@ -700,6 +716,38 @@ export const makeMessagesSocket = (config) => {
|
|
|
700
716
|
statusJidList: options.statusJidList,
|
|
701
717
|
additionalNodes
|
|
702
718
|
});
|
|
719
|
+
// AunuBaileys: kirim isi album sebagai pesan terasosiasi (dari @itsliaaa/baileys)
|
|
720
|
+
if ('album' in content) {
|
|
721
|
+
const { delayMs = 1500 } = options;
|
|
722
|
+
for (const albumMedia of content.album) {
|
|
723
|
+
const albumMsg = await generateWAMessage(jid, albumMedia, {
|
|
724
|
+
logger,
|
|
725
|
+
userJid,
|
|
726
|
+
upload: (fp, opts) => waUploadToServer(fp, { ...opts, newsletter: isJidNewsletter(jid) }),
|
|
727
|
+
mediaCache: config.mediaCache,
|
|
728
|
+
options: config.options,
|
|
729
|
+
...options,
|
|
730
|
+
messageId: generateMessageIDV2(sock.user?.id)
|
|
731
|
+
});
|
|
732
|
+
const normalized = normalizeMessageContent(albumMsg.message);
|
|
733
|
+
if (!normalized || !('imageMessage' in normalized || 'videoMessage' in normalized)) {
|
|
734
|
+
throw new Boom('Invalid message type for album', { statusCode: 400 });
|
|
735
|
+
}
|
|
736
|
+
albumMsg.message.messageContextInfo = albumMsg.message.messageContextInfo || {};
|
|
737
|
+
albumMsg.message.messageContextInfo.messageAssociation = {
|
|
738
|
+
parentMessageKey: fullMsg.key,
|
|
739
|
+
associationType: proto.MessageAssociation.AssociationType.MEDIA_ALBUM
|
|
740
|
+
};
|
|
741
|
+
await relayMessage(jid, albumMsg.message, {
|
|
742
|
+
messageId: albumMsg.key.id,
|
|
743
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
744
|
+
statusJidList: options.statusJidList,
|
|
745
|
+
additionalAttributes,
|
|
746
|
+
additionalNodes
|
|
747
|
+
});
|
|
748
|
+
await delay(delayMs);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
703
751
|
if (config.emitOwnEvents) {
|
|
704
752
|
process.nextTick(() => {
|
|
705
753
|
processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Boom from '@hapi/boom';
|
|
1
2
|
import { QueryIds, XWAPaths } from '../Types/index.js';
|
|
2
3
|
import { generateProfilePicture } from '../Utils/messages-media.js';
|
|
3
4
|
import { getBinaryNodeChild } from '../WABinary/index.js';
|
|
@@ -49,6 +50,13 @@ export const makeNewsletterSocket = (sock) => {
|
|
|
49
50
|
};
|
|
50
51
|
return {
|
|
51
52
|
...sock,
|
|
53
|
+
// AunuBaileys: ambil ID numerik dari JID newsletter
|
|
54
|
+
newsletterId: (jid) => {
|
|
55
|
+
if (!jid || !jid.endsWith('@newsletter')) {
|
|
56
|
+
throw new Boom('Invalid newsletter jid', { statusCode: 400 });
|
|
57
|
+
}
|
|
58
|
+
return jid.split('@')[0];
|
|
59
|
+
},
|
|
52
60
|
newsletterCreate: async (name, description) => {
|
|
53
61
|
const variables = {
|
|
54
62
|
input: {
|
package/lib/Socket/socket.js
CHANGED
|
@@ -4,7 +4,9 @@ import { URL } from 'url';
|
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
6
|
import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, NOISE_WA_HEADER } from '../Defaults/index.js';
|
|
7
|
-
import { DisconnectReason } from '../Types/index.js'
|
|
7
|
+
import { DisconnectReason } from '../Types/index.js'
|
|
8
|
+
import { executeWMexQuery } from './mex.js';
|
|
9
|
+
import { QueryIds, XWAPaths } from '../Types/index.js';
|
|
8
10
|
import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getErrorCodeFromStreamError, getNextPreKeysNode, getPlatformId, makeEventBuffer, makeNoiseHandler, promiseTimeout } from '../Utils/index.js';
|
|
9
11
|
import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getBinaryNodeChild, getBinaryNodeChildren, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
10
12
|
import { WebSocketClient } from './Client/index.js';
|
|
@@ -191,7 +193,15 @@ export const makeSocket = (config) => {
|
|
|
191
193
|
await keys.transaction(async () => {
|
|
192
194
|
logger.info({ count }, 'uploading pre-keys');
|
|
193
195
|
const { update, node } = await getNextPreKeysNode({ creds, keys }, count);
|
|
194
|
-
|
|
196
|
+
// AunuBaileys: timeout upload pre-keys agar koneksi tidak menggantung (dari MichelleBot/baileys)
|
|
197
|
+
await promiseTimeout(30000, async (resolve, reject) => {
|
|
198
|
+
try {
|
|
199
|
+
resolve(await query(node));
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
reject(error);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
195
205
|
ev.emit('creds.update', update);
|
|
196
206
|
logger.info({ count }, 'uploaded pre-keys');
|
|
197
207
|
});
|
|
@@ -234,6 +244,11 @@ export const makeSocket = (config) => {
|
|
|
234
244
|
}
|
|
235
245
|
});
|
|
236
246
|
};
|
|
247
|
+
// AunuBaileys: socket end handlers (pola v7) + fetch Mex (dari @itsliaaa/baileys)
|
|
248
|
+
const socketEndHandlers = [];
|
|
249
|
+
const registerSocketEndHandler = (handler) => {
|
|
250
|
+
socketEndHandlers.push(handler);
|
|
251
|
+
};
|
|
237
252
|
const end = (error) => {
|
|
238
253
|
if (closed) {
|
|
239
254
|
logger.trace({ trace: error?.stack }, 'connection already closed');
|
|
@@ -259,6 +274,12 @@ export const makeSocket = (config) => {
|
|
|
259
274
|
date: new Date()
|
|
260
275
|
}
|
|
261
276
|
});
|
|
277
|
+
for (const handler of socketEndHandlers) {
|
|
278
|
+
try {
|
|
279
|
+
handler();
|
|
280
|
+
}
|
|
281
|
+
catch { }
|
|
282
|
+
}
|
|
262
283
|
ev.removeAllListeners('connection.update');
|
|
263
284
|
};
|
|
264
285
|
const waitForSocketOpen = async () => {
|
|
@@ -569,6 +590,21 @@ export const makeSocket = (config) => {
|
|
|
569
590
|
}
|
|
570
591
|
Object.assign(creds, update);
|
|
571
592
|
});
|
|
593
|
+
const fetchAccountReachoutTimelock = async () => {
|
|
594
|
+
const queryResult = await executeWMexQuery({}, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
|
|
595
|
+
const result = {
|
|
596
|
+
isActive: !!queryResult?.is_active,
|
|
597
|
+
timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
|
|
598
|
+
? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
|
|
599
|
+
: undefined,
|
|
600
|
+
enforcementType: queryResult?.enforcement_type ?? 'DEFAULT'
|
|
601
|
+
};
|
|
602
|
+
ev.emit('connection.update', { reachoutTimeLock: result });
|
|
603
|
+
return result;
|
|
604
|
+
};
|
|
605
|
+
const fetchNewChatMessageCap = async () => {
|
|
606
|
+
return executeWMexQuery({ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } }, QueryIds.MESSAGE_CAPPING_INFO, XWAPaths.xwa2_message_capping_info, query, generateMessageTag);
|
|
607
|
+
};
|
|
572
608
|
return {
|
|
573
609
|
type: 'md',
|
|
574
610
|
ws,
|
|
@@ -586,6 +622,9 @@ export const makeSocket = (config) => {
|
|
|
586
622
|
sendNode,
|
|
587
623
|
logout,
|
|
588
624
|
end,
|
|
625
|
+
registerSocketEndHandler,
|
|
626
|
+
fetchAccountReachoutTimelock,
|
|
627
|
+
fetchNewChatMessageCap,
|
|
589
628
|
onUnexpectedError,
|
|
590
629
|
uploadPreKeys,
|
|
591
630
|
uploadPreKeysToServerIfRequired,
|
package/lib/Types/Message.d.ts
CHANGED
|
@@ -172,7 +172,22 @@ export type AnyRegularMessageContent = (({
|
|
|
172
172
|
body?: string;
|
|
173
173
|
footer?: string;
|
|
174
174
|
} | SharePhoneNumber | RequestPhoneNumber) & ViewOnce;
|
|
175
|
-
export type
|
|
175
|
+
export type StickerPackStickerInfo = {
|
|
176
|
+
data: WAMediaUpload;
|
|
177
|
+
emojis?: string[];
|
|
178
|
+
isAnimated?: boolean;
|
|
179
|
+
accessibilityLabel?: string;
|
|
180
|
+
isLottie?: boolean;
|
|
181
|
+
};
|
|
182
|
+
export type StickerPackInfo = {
|
|
183
|
+
stickers: StickerPackStickerInfo[];
|
|
184
|
+
cover: WAMediaUpload;
|
|
185
|
+
name?: string;
|
|
186
|
+
publisher?: string;
|
|
187
|
+
packId?: string;
|
|
188
|
+
description?: string;
|
|
189
|
+
};
|
|
190
|
+
export type AnyMessageContent = (AnyRegularMessageContent | {
|
|
176
191
|
forward: WAMessage;
|
|
177
192
|
force?: boolean;
|
|
178
193
|
} | {
|
|
@@ -180,6 +195,22 @@ export type AnyMessageContent = AnyRegularMessageContent | {
|
|
|
180
195
|
delete: WAMessageKey;
|
|
181
196
|
} | {
|
|
182
197
|
disappearingMessagesInChat: boolean | number;
|
|
198
|
+
} | {
|
|
199
|
+
/** AunuBaileys: send a sticker pack (cover + stickers) */
|
|
200
|
+
stickerPack: StickerPackInfo;
|
|
201
|
+
} | {
|
|
202
|
+
/** AunuBaileys: send a sticker pack, flat form (cover + stickers) */
|
|
203
|
+
stickers: StickerPackStickerInfo[];
|
|
204
|
+
cover: WAMediaUpload;
|
|
205
|
+
name?: string;
|
|
206
|
+
publisher?: string;
|
|
207
|
+
description?: string;
|
|
208
|
+
} | {
|
|
209
|
+
/** AunuBaileys: send an album of images/videos */
|
|
210
|
+
album: AnyRegularMessageContent[];
|
|
211
|
+
}) & {
|
|
212
|
+
/** AunuBaileys: mark the message with the AI label (private chats only) */
|
|
213
|
+
ai?: boolean;
|
|
183
214
|
};
|
|
184
215
|
export type GroupMetadataParticipants = Pick<GroupMetadata, 'participants'>;
|
|
185
216
|
type MinimalRelayOptions = {
|
package/lib/Types/Newsletter.js
CHANGED
|
@@ -12,6 +12,8 @@ export var XWAPaths;
|
|
|
12
12
|
XWAPaths["xwa2_newsletter_change_owner"] = "xwa2_newsletter_change_owner";
|
|
13
13
|
XWAPaths["xwa2_newsletter_demote"] = "xwa2_newsletter_demote";
|
|
14
14
|
XWAPaths["xwa2_newsletter_delete_v2"] = "xwa2_newsletter_delete_v2";
|
|
15
|
+
XWAPaths["xwa2_fetch_account_reachout_timelock"] = "xwa2_fetch_account_reachout_timelock";
|
|
16
|
+
XWAPaths["xwa2_message_capping_info"] = "xwa2_message_capping_info";
|
|
15
17
|
})(XWAPaths || (XWAPaths = {}));
|
|
16
18
|
export var QueryIds;
|
|
17
19
|
(function (QueryIds) {
|
|
@@ -27,5 +29,7 @@ export var QueryIds;
|
|
|
27
29
|
QueryIds["CHANGE_OWNER"] = "7341777602580933";
|
|
28
30
|
QueryIds["DEMOTE"] = "6551828931592903";
|
|
29
31
|
QueryIds["DELETE"] = "30062808666639665";
|
|
32
|
+
QueryIds["REACHOUT_TIMELOCK"] = "23983697327930364";
|
|
33
|
+
QueryIds["MESSAGE_CAPPING_INFO"] = "24503548349331633";
|
|
30
34
|
})(QueryIds || (QueryIds = {}));
|
|
31
35
|
//# sourceMappingURL=Newsletter.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AnyMessageContent, MiscMessageGenerationOptions, WAMessage, WASocket } from '../Types';
|
|
2
|
+
export declare class AunuHandler {
|
|
3
|
+
sock: WASocket;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly brand: string;
|
|
6
|
+
constructor(sock: WASocket);
|
|
7
|
+
send(jid: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WAMessage | undefined>;
|
|
8
|
+
reply(jid: string, content: AnyMessageContent, quoted: WAMessage, options?: MiscMessageGenerationOptions): Promise<WAMessage | undefined>;
|
|
9
|
+
react(jid: string, emoji: string, key: WAMessage['key']): Promise<WAMessage | undefined>;
|
|
10
|
+
newsletterId(jid: string): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AunuHandler — lapisan kenyamanan khas AunuBaileys di atas socket.
|
|
3
|
+
* Diekspos sebagai `sock.aunuHandler` dan diekspor sebagai kelas dari paket.
|
|
4
|
+
*/
|
|
5
|
+
export class AunuHandler {
|
|
6
|
+
constructor(sock) {
|
|
7
|
+
this.sock = sock;
|
|
8
|
+
this.name = 'AunuBaileys';
|
|
9
|
+
this.brand = 'AunuCore Creative Network';
|
|
10
|
+
}
|
|
11
|
+
/** Kirim pesan apa pun (delegate ke sock.sendMessage). */
|
|
12
|
+
async send(jid, content, options) {
|
|
13
|
+
return this.sock.sendMessage(jid, content, options);
|
|
14
|
+
}
|
|
15
|
+
/** Balas sebuah pesan (quote). */
|
|
16
|
+
async reply(jid, content, quoted, options = {}) {
|
|
17
|
+
return this.sock.sendMessage(jid, content, { ...options, quoted });
|
|
18
|
+
}
|
|
19
|
+
/** Beri reaksi emoji ke sebuah pesan. */
|
|
20
|
+
async react(jid, emoji, key) {
|
|
21
|
+
return this.sock.sendMessage(jid, { react: { text: emoji, key } });
|
|
22
|
+
}
|
|
23
|
+
/** ID numerik dari JID newsletter. */
|
|
24
|
+
newsletterId(jid) {
|
|
25
|
+
return this.sock.newsletterId(jid);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -109,4 +109,5 @@ export declare const decryptMediaRetryData: ({ ciphertext, iv }: {
|
|
|
109
109
|
}, mediaKey: Uint8Array, msgId: string) => Promise<proto.MediaRetryNotification>;
|
|
110
110
|
export declare const getStatusCodeForMediaRetry: (code: number) => 200 | 412 | 404 | 418;
|
|
111
111
|
export {};
|
|
112
|
-
//# sourceMappingURL=messages-media.d.ts.map
|
|
112
|
+
//# sourceMappingURL=messages-media.d.ts.map
|
|
113
|
+
export declare const getImageProcessingLibrary: () => Promise<Record<string, any>>;
|
|
@@ -9,12 +9,12 @@ import { join } from 'path';
|
|
|
9
9
|
import { Readable, Transform } from 'stream';
|
|
10
10
|
import { URL } from 'url';
|
|
11
11
|
import { proto } from '../../WAProto/index.js';
|
|
12
|
-
import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults/index.js';
|
|
12
|
+
import { DEFAULT_ORIGIN, NEWSLETTER_MEDIA_PATH_MAP, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults/index.js';
|
|
13
13
|
import { getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary/index.js';
|
|
14
14
|
import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto.js';
|
|
15
15
|
import { generateMessageIDV2 } from './generics.js';
|
|
16
16
|
const getTmpFilesDirectory = () => tmpdir();
|
|
17
|
-
const getImageProcessingLibrary = async () => {
|
|
17
|
+
export const getImageProcessingLibrary = async () => {
|
|
18
18
|
//@ts-ignore
|
|
19
19
|
const [jimp, sharp] = await Promise.all([import('jimp').catch(() => { }), import('sharp').catch(() => { })]);
|
|
20
20
|
if (sharp) {
|
|
@@ -495,7 +495,7 @@ export function extensionForMediaMessage(message) {
|
|
|
495
495
|
return extension;
|
|
496
496
|
}
|
|
497
497
|
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
|
|
498
|
-
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
|
498
|
+
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs, newsletter }) => {
|
|
499
499
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
500
500
|
let uploadInfo = await refreshMediaConn(false);
|
|
501
501
|
let urls;
|
|
@@ -504,7 +504,14 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, opt
|
|
|
504
504
|
for (const { hostname } of hosts) {
|
|
505
505
|
logger.debug(`uploading to "${hostname}"`);
|
|
506
506
|
const auth = encodeURIComponent(uploadInfo.auth); // the auth token
|
|
507
|
-
const
|
|
507
|
+
const mediaPathMap = newsletter ? NEWSLETTER_MEDIA_PATH_MAP : MEDIA_PATH_MAP;
|
|
508
|
+
let url = `https://${hostname}${mediaPathMap[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
509
|
+
if (newsletter) {
|
|
510
|
+
url += '&server_thumb_gen=1';
|
|
511
|
+
if (mediaType === 'video' || mediaType === 'gif' || mediaType === 'ptv') {
|
|
512
|
+
url += '&server_transcode=1';
|
|
513
|
+
}
|
|
514
|
+
}
|
|
508
515
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
509
516
|
let result;
|
|
510
517
|
try {
|
package/lib/Utils/messages.js
CHANGED
|
@@ -3,13 +3,14 @@ import axios from 'axios';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { promises as fs } from 'fs';
|
|
5
5
|
import {} from 'stream';
|
|
6
|
+
import { zip } from 'fflate';
|
|
6
7
|
import { proto } from '../../WAProto/index.js';
|
|
7
8
|
import { MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
8
9
|
import { WAMessageStatus, WAProto } from '../Types/index.js';
|
|
9
10
|
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
|
|
10
11
|
import { sha256 } from './crypto.js';
|
|
11
12
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
12
|
-
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
|
|
13
|
+
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData, getImageProcessingLibrary, getStream, toBuffer } from './messages-media.js';
|
|
13
14
|
const MIMETYPE_MAP = {
|
|
14
15
|
image: 'image/jpeg',
|
|
15
16
|
video: 'video/mp4',
|
|
@@ -257,6 +258,205 @@ export const generateForwardMessageContent = (message, forceForward) => {
|
|
|
257
258
|
}
|
|
258
259
|
return content;
|
|
259
260
|
};
|
|
261
|
+
// AunuBaileys: StickerPack (diadaptasi dari neoxr/baileys & @itsliaaa/baileys)
|
|
262
|
+
function isWebPBuffer(buffer) {
|
|
263
|
+
return (buffer.length >= 12 &&
|
|
264
|
+
buffer[0] === 0x52 &&
|
|
265
|
+
buffer[1] === 0x49 &&
|
|
266
|
+
buffer[2] === 0x46 &&
|
|
267
|
+
buffer[3] === 0x46 &&
|
|
268
|
+
buffer[8] === 0x57 &&
|
|
269
|
+
buffer[9] === 0x45 &&
|
|
270
|
+
buffer[10] === 0x42 &&
|
|
271
|
+
buffer[11] === 0x50);
|
|
272
|
+
}
|
|
273
|
+
function isAnimatedWebP(buffer) {
|
|
274
|
+
// WebP must start with RIFF....WEBP
|
|
275
|
+
if (buffer.length < 12 ||
|
|
276
|
+
buffer[0] !== 0x52 ||
|
|
277
|
+
buffer[1] !== 0x49 ||
|
|
278
|
+
buffer[2] !== 0x46 ||
|
|
279
|
+
buffer[3] !== 0x46 ||
|
|
280
|
+
buffer[8] !== 0x57 ||
|
|
281
|
+
buffer[9] !== 0x45 ||
|
|
282
|
+
buffer[10] !== 0x42 ||
|
|
283
|
+
buffer[11] !== 0x50) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
// Parse chunks starting after RIFF header (12 bytes)
|
|
287
|
+
let offset = 12;
|
|
288
|
+
while (offset < buffer.length - 8) {
|
|
289
|
+
const chunkFourCC = buffer.toString('ascii', offset, offset + 4);
|
|
290
|
+
const chunkSize = buffer.readUInt32LE(offset + 4);
|
|
291
|
+
if (chunkFourCC === 'VP8X') {
|
|
292
|
+
// VP8X extended header, check animation flag (bit 1 at offset+8)
|
|
293
|
+
const flagsOffset = offset + 8;
|
|
294
|
+
if (flagsOffset < buffer.length) {
|
|
295
|
+
const flags = buffer[flagsOffset];
|
|
296
|
+
if (flags & 0x02) {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
else if (chunkFourCC === 'ANIM' || chunkFourCC === 'ANMF') {
|
|
302
|
+
// ANIM or ANMF chunks indicate animation
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
// Move to next chunk (chunk size + 8 bytes header, padded to even)
|
|
306
|
+
offset += 8 + chunkSize + (chunkSize % 2);
|
|
307
|
+
}
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
async function prepareStickerPackMessage(stickerPack, options) {
|
|
311
|
+
const { stickers, name, publisher, packId, description } = stickerPack;
|
|
312
|
+
if (stickers.length > 60) {
|
|
313
|
+
throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
314
|
+
}
|
|
315
|
+
if (stickers.length === 0) {
|
|
316
|
+
throw new Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
|
|
317
|
+
}
|
|
318
|
+
const stickerPackIdValue = packId || generateMessageIDV2();
|
|
319
|
+
const lib = await getImageProcessingLibrary();
|
|
320
|
+
const stickerData = {};
|
|
321
|
+
const stickerPromises = stickers.map(async (s, i) => {
|
|
322
|
+
try {
|
|
323
|
+
const { stream } = await getStream(s.data);
|
|
324
|
+
const buffer = await toBuffer(stream);
|
|
325
|
+
let webpBuffer;
|
|
326
|
+
let isAnimated = false;
|
|
327
|
+
const isWebP = isWebPBuffer(buffer);
|
|
328
|
+
if (isWebP) {
|
|
329
|
+
// Already WebP - preserve original to keep exif metadata and animation
|
|
330
|
+
webpBuffer = buffer;
|
|
331
|
+
isAnimated = isAnimatedWebP(buffer);
|
|
332
|
+
}
|
|
333
|
+
else if ('sharp' in lib && lib.sharp) {
|
|
334
|
+
// Convert to WebP, preserving metadata
|
|
335
|
+
webpBuffer = await lib.sharp.default(buffer).webp().toBuffer();
|
|
336
|
+
// Non-WebP inputs converted to WebP are not animated
|
|
337
|
+
isAnimated = false;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
throw new Boom('No image processing library (sharp) available for converting sticker to WebP. Either install sharp or provide stickers in WebP format.');
|
|
341
|
+
}
|
|
342
|
+
if (webpBuffer.length > 1024 * 1024) {
|
|
343
|
+
throw new Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
|
|
344
|
+
}
|
|
345
|
+
const hash = sha256(webpBuffer).toString('base64').replace(/\//g, '-');
|
|
346
|
+
const fileName = `${hash}.webp`;
|
|
347
|
+
stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
|
|
348
|
+
return {
|
|
349
|
+
fileName,
|
|
350
|
+
mimetype: 'image/webp',
|
|
351
|
+
isAnimated: s.isAnimated || isAnimated,
|
|
352
|
+
emojis: s.emojis || [],
|
|
353
|
+
accessibilityLabel: s.accessibilityLabel || '',
|
|
354
|
+
isLottie: s.isLottie || false
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
options.logger?.warn(`Skipping sticker ${i}: ${e.message}`);
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
const stickerMetadata = (await Promise.all(stickerPromises)).filter(Boolean);
|
|
363
|
+
// Process and add cover/tray icon to the ZIP
|
|
364
|
+
const trayIconFileName = `${stickerPackIdValue}.webp`;
|
|
365
|
+
const { stream: coverStream } = await getStream(stickerPack.cover);
|
|
366
|
+
const coverBuffer = await toBuffer(coverStream);
|
|
367
|
+
let coverWebpBuffer;
|
|
368
|
+
const isCoverWebP = isWebPBuffer(coverBuffer);
|
|
369
|
+
if (isCoverWebP) {
|
|
370
|
+
// Already WebP - preserve original to keep exif metadata
|
|
371
|
+
coverWebpBuffer = coverBuffer;
|
|
372
|
+
}
|
|
373
|
+
else if ('sharp' in lib && lib.sharp) {
|
|
374
|
+
coverWebpBuffer = await lib.sharp.default(coverBuffer).webp().toBuffer();
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
throw new Boom('No image processing library (sharp) available for converting cover to WebP. Either install sharp or provide cover in WebP format.');
|
|
378
|
+
}
|
|
379
|
+
// Add cover to ZIP data
|
|
380
|
+
stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
|
|
381
|
+
const zipBuffer = await new Promise((resolve, reject) => {
|
|
382
|
+
zip(stickerData, (err, data) => {
|
|
383
|
+
if (err) {
|
|
384
|
+
reject(err);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
resolve(Buffer.from(data));
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
const stickerPackSize = zipBuffer.length;
|
|
392
|
+
const stickerPackUpload = await encryptedStream(zipBuffer, 'sticker-pack', {
|
|
393
|
+
logger: options.logger,
|
|
394
|
+
opts: options.options
|
|
395
|
+
});
|
|
396
|
+
const stickerPackUploadResult = await options.upload(stickerPackUpload.encFilePath, {
|
|
397
|
+
fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
|
|
398
|
+
mediaType: 'sticker-pack',
|
|
399
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
400
|
+
});
|
|
401
|
+
await fs.unlink(stickerPackUpload.encFilePath);
|
|
402
|
+
const stickerPackMessage = {
|
|
403
|
+
name: name,
|
|
404
|
+
publisher: publisher,
|
|
405
|
+
stickerPackId: stickerPackIdValue,
|
|
406
|
+
packDescription: description,
|
|
407
|
+
stickerPackOrigin: WAProto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED,
|
|
408
|
+
stickerPackSize: stickerPackSize,
|
|
409
|
+
stickers: stickerMetadata,
|
|
410
|
+
fileSha256: stickerPackUpload.fileSha256,
|
|
411
|
+
fileEncSha256: stickerPackUpload.fileEncSha256,
|
|
412
|
+
mediaKey: stickerPackUpload.mediaKey,
|
|
413
|
+
directPath: stickerPackUploadResult.directPath,
|
|
414
|
+
fileLength: stickerPackUpload.fileLength,
|
|
415
|
+
mediaKeyTimestamp: unixTimestampSeconds(),
|
|
416
|
+
trayIconFileName: trayIconFileName
|
|
417
|
+
};
|
|
418
|
+
try {
|
|
419
|
+
// Reuse the cover buffer we already processed for thumbnail generation
|
|
420
|
+
let thumbnailBuffer;
|
|
421
|
+
if ('sharp' in lib && lib.sharp) {
|
|
422
|
+
thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
|
|
423
|
+
}
|
|
424
|
+
else if ('jimp' in lib && lib.jimp) {
|
|
425
|
+
const jimpImage = await lib.jimp.Jimp.read(coverBuffer);
|
|
426
|
+
thumbnailBuffer = await jimpImage.resize({ w: 252, h: 252 }).getBuffer('image/jpeg');
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
throw new Error('No image processing library available for thumbnail generation');
|
|
430
|
+
}
|
|
431
|
+
if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
|
|
432
|
+
throw new Error('Failed to generate thumbnail buffer');
|
|
433
|
+
}
|
|
434
|
+
const thumbUpload = await encryptedStream(thumbnailBuffer, 'thumbnail-sticker-pack', {
|
|
435
|
+
logger: options.logger,
|
|
436
|
+
opts: options.options,
|
|
437
|
+
mediaKey: stickerPackUpload.mediaKey // Use same mediaKey as the sticker pack ZIP
|
|
438
|
+
});
|
|
439
|
+
const thumbUploadResult = await options.upload(thumbUpload.encFilePath, {
|
|
440
|
+
fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
|
|
441
|
+
mediaType: 'thumbnail-sticker-pack',
|
|
442
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
443
|
+
});
|
|
444
|
+
await fs.unlink(thumbUpload.encFilePath);
|
|
445
|
+
Object.assign(stickerPackMessage, {
|
|
446
|
+
thumbnailDirectPath: thumbUploadResult.directPath,
|
|
447
|
+
thumbnailSha256: thumbUpload.fileSha256,
|
|
448
|
+
thumbnailEncSha256: thumbUpload.fileEncSha256,
|
|
449
|
+
thumbnailHeight: 252,
|
|
450
|
+
thumbnailWidth: 252,
|
|
451
|
+
imageDataHash: sha256(thumbnailBuffer).toString('base64')
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
catch (e) {
|
|
455
|
+
options.logger?.warn?.(`Thumbnail generation failed: ${e}`);
|
|
456
|
+
}
|
|
457
|
+
return { stickerPackMessage };
|
|
458
|
+
}
|
|
459
|
+
|
|
260
460
|
export const generateWAMessageContent = async (message, options) => {
|
|
261
461
|
var _a, _b;
|
|
262
462
|
let m = {};
|
|
@@ -415,6 +615,23 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
415
615
|
// poll v2 is for community announcement groups (single select and multiple)
|
|
416
616
|
m.pollCreationMessageV2 = pollCreationMessage;
|
|
417
617
|
}
|
|
618
|
+
else if (message.poll.pollType === 1) {
|
|
619
|
+
// AunuBaileys: kuis (dari @itsliaaa/baileys) — untuk newsletter
|
|
620
|
+
if (!message.poll.correctAnswer) {
|
|
621
|
+
throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
|
|
622
|
+
}
|
|
623
|
+
// proto 6.7.24: V5 adalah FutureProofMessage — konten dibungkus di .message
|
|
624
|
+
m.pollCreationMessageV5 = {
|
|
625
|
+
message: {
|
|
626
|
+
pollCreationMessage: {
|
|
627
|
+
...pollCreationMessage,
|
|
628
|
+
correctAnswer: { optionName: message.poll.correctAnswer.toString() },
|
|
629
|
+
pollType: 1,
|
|
630
|
+
selectableOptionsCount: 1
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
}
|
|
418
635
|
else {
|
|
419
636
|
if (message.poll.selectableCount === 1) {
|
|
420
637
|
//poll v3 is for single select polls
|
|
@@ -426,6 +643,62 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
426
643
|
}
|
|
427
644
|
}
|
|
428
645
|
}
|
|
646
|
+
else if ('pollResult' in message) {
|
|
647
|
+
// AunuBaileys: poll result snapshot (dari @itsliaaa/baileys)
|
|
648
|
+
const pollResultSnapshotMessage = {
|
|
649
|
+
name: message.pollResult.name,
|
|
650
|
+
pollVotes: message.pollResult.votes.map(vote => ({
|
|
651
|
+
optionName: vote.name,
|
|
652
|
+
optionVoteCount: parseInt(vote.voteCount)
|
|
653
|
+
}))
|
|
654
|
+
};
|
|
655
|
+
if (message.pollResult.pollType === 1) {
|
|
656
|
+
pollResultSnapshotMessage.pollType = proto.Message.PollCreationMessage.PollType.QUIZ;
|
|
657
|
+
m.pollResultSnapshotMessageV3 = pollResultSnapshotMessage;
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
pollResultSnapshotMessage.pollType = proto.Message.PollCreationMessage.PollType.POLL;
|
|
661
|
+
m.pollResultSnapshotMessage = pollResultSnapshotMessage;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
else if ('pollUpdate' in message) {
|
|
665
|
+
if (!message.pollUpdate.key) {
|
|
666
|
+
throw new Boom('Message key is required', { statusCode: 400 });
|
|
667
|
+
}
|
|
668
|
+
if (!message.pollUpdate.vote) {
|
|
669
|
+
throw new Boom('Encrypted vote payload is required', { statusCode: 400 });
|
|
670
|
+
}
|
|
671
|
+
m.pollUpdateMessage = {
|
|
672
|
+
metadata: message.pollUpdate.metadata,
|
|
673
|
+
pollCreationMessageKey: message.pollUpdate.key,
|
|
674
|
+
senderTimestampMs: Date.now(),
|
|
675
|
+
vote: message.pollUpdate.vote
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
else if ('paymentInviteServiceType' in message) {
|
|
679
|
+
// AunuBaileys: payment invite (dari @itsliaaa/baileys)
|
|
680
|
+
m.paymentInviteMessage = {
|
|
681
|
+
expiryTimestamp: Date.now(),
|
|
682
|
+
serviceType: message.paymentInviteServiceType
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
else if ('orderText' in message) {
|
|
686
|
+
// AunuBaileys: order message (dari @itsliaaa/baileys)
|
|
687
|
+
if (message.thumbnail !== undefined && !Buffer.isBuffer(message.thumbnail)) {
|
|
688
|
+
throw new Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
|
|
689
|
+
}
|
|
690
|
+
m.orderMessage = {
|
|
691
|
+
itemCount: message.itemCount || 1,
|
|
692
|
+
messageVersion: 1,
|
|
693
|
+
orderTitle: message.orderTitle || 'AunuBaileys',
|
|
694
|
+
status: proto.Message.OrderMessage.OrderStatus.INQUIRY,
|
|
695
|
+
surface: proto.Message.OrderMessage.OrderSurface.CATALOG,
|
|
696
|
+
totalAmount1000: message.totalAmount1000 || 1000,
|
|
697
|
+
totalCurrencyCode: message.currency || 'IDR',
|
|
698
|
+
thumbnail: message.thumbnail,
|
|
699
|
+
message: message.orderText
|
|
700
|
+
};
|
|
701
|
+
}
|
|
429
702
|
else if ('sharePhoneNumber' in message) {
|
|
430
703
|
m.protocolMessage = {
|
|
431
704
|
type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
@@ -434,6 +707,28 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
434
707
|
else if ('requestPhoneNumber' in message) {
|
|
435
708
|
m.requestPhoneNumberMessage = {};
|
|
436
709
|
}
|
|
710
|
+
else if ('album' in message) {
|
|
711
|
+
// AunuBaileys: album message (dari @itsliaaa/baileys)
|
|
712
|
+
if (!Array.isArray(message.album)) {
|
|
713
|
+
throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
|
|
714
|
+
}
|
|
715
|
+
let videoCount = 0;
|
|
716
|
+
let imageCount = 0;
|
|
717
|
+
for (const item of message.album) {
|
|
718
|
+
if (item.video) videoCount++;
|
|
719
|
+
if (item.image) imageCount++;
|
|
720
|
+
}
|
|
721
|
+
if (videoCount + imageCount < 2) {
|
|
722
|
+
throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
|
|
723
|
+
}
|
|
724
|
+
m.albumMessage = { expectedImageCount: imageCount, expectedVideoCount: videoCount };
|
|
725
|
+
}
|
|
726
|
+
else if ('stickerPack' in message) {
|
|
727
|
+
m = await prepareStickerPackMessage(message.stickerPack, options);
|
|
728
|
+
}
|
|
729
|
+
else if ('stickers' in message && 'cover' in message) {
|
|
730
|
+
m = await prepareStickerPackMessage(message, options);
|
|
731
|
+
}
|
|
437
732
|
else {
|
|
438
733
|
m = await prepareWAMessageMedia(message, options);
|
|
439
734
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Mutex } from 'async-mutex';
|
|
2
|
-
import { mkdir, readFile, stat, unlink, writeFile } from 'fs/promises';
|
|
2
|
+
import { mkdir, readFile, rename, stat, unlink, writeFile } from 'fs/promises';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
5
|
import { initAuthCreds } from './auth-utils.js';
|
|
@@ -32,7 +32,10 @@ export const useMultiFileAuthState = async (folder) => {
|
|
|
32
32
|
const mutex = getFileLock(filePath);
|
|
33
33
|
return mutex.acquire().then(async (release) => {
|
|
34
34
|
try {
|
|
35
|
-
|
|
35
|
+
// AunuBaileys: atomic write (tmp + rename) anti-korupsi sesi — terinspirasi @itsliaaa/baileys
|
|
36
|
+
const tmpPath = `${filePath}.tmp-${process.pid}`;
|
|
37
|
+
await writeFile(tmpPath, JSON.stringify(data, BufferJSON.replacer));
|
|
38
|
+
await rename(tmpPath, filePath);
|
|
36
39
|
}
|
|
37
40
|
finally {
|
|
38
41
|
release();
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
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.3",
|
|
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",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"pino": "^9.6",
|
|
47
47
|
"protobufjs": "^7.2.4",
|
|
48
48
|
"ws": "^8.13.0",
|
|
49
|
-
"@adiwajshing/keyed-db": "^0.2.4"
|
|
49
|
+
"@adiwajshing/keyed-db": "^0.2.4",
|
|
50
|
+
"fflate": "^0.8.2"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@eslint/eslintrc": "^3.3.1",
|