@pontalabs/baileys 1.2.3 → 1.2.5
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 +479 -605
- package/lib/Socket/messages-send.js +147 -10
- package/lib/Utils/mbuilder.d.ts +9 -3
- package/lib/Utils/mbuilder.js +25 -14
- package/lib/Utils/rich-message-utils.js +31 -1
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
|
14
14
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
15
15
|
import kikyy from './dugong.js';
|
|
16
16
|
import { generateTableContent, generateTableContentV2, generateListContent, generateCodeBlockContent, generateCodeBlockContentV2, generateLinkContent, generateLinkContentV2, generateRichMessageContent, generateUnifiedResponseContent, captureUnifiedResponse, generateLatexContent, generateLatexImageContent, generateLatexInlineImageContent } from '../Utils/rich-message-utils.js';
|
|
17
|
+
import { AIRich, Button, ButtonV2, Carousel } from '../Utils/mbuilder.js';
|
|
17
18
|
export const makeMessagesSocket = (config) => {
|
|
18
19
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
19
20
|
const sock = makeNewsletterSocket(config);
|
|
@@ -1132,20 +1133,156 @@ export const makeMessagesSocket = (config) => {
|
|
|
1132
1133
|
sendMessage: sendMessageImpl = async (jid, content, options = {}) => {
|
|
1133
1134
|
const userJid = authState.creds.me.id;
|
|
1134
1135
|
|
|
1135
|
-
// `
|
|
1136
|
-
//
|
|
1137
|
-
//
|
|
1138
|
-
|
|
1136
|
+
// `items` may contain Rich AI build descriptors as well as the
|
|
1137
|
+
// interactive builders exported by mbuilder.js. When buildDelay is
|
|
1138
|
+
// enabled, keep ONE WhatsApp message id and progressively edit that
|
|
1139
|
+
// message instead of sending a new bubble for every item.
|
|
1140
|
+
if (content && !Array.isArray(jid) && Array.isArray(content.items) && content.items.length > 0) {
|
|
1141
|
+
const items = content.items;
|
|
1139
1142
|
const buildDelay = Number(options.buildDelay ?? content.buildDelay ?? 0);
|
|
1140
|
-
|
|
1143
|
+
const hasDelay = Number.isFinite(buildDelay) && buildDelay > 0;
|
|
1144
|
+
const isInteractiveBuilder = (item) => item instanceof Button || item instanceof ButtonV2 || item instanceof Carousel;
|
|
1145
|
+
const isAIRichBuilder = (item) => item instanceof AIRich;
|
|
1146
|
+
const hasInteractiveBuilder = items.some(isInteractiveBuilder);
|
|
1147
|
+
|
|
1148
|
+
if (hasDelay || hasInteractiveBuilder) {
|
|
1141
1149
|
const sendOptions = { ...options };
|
|
1142
1150
|
delete sendOptions.buildDelay;
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1151
|
+
delete sendOptions.additionalNodes;
|
|
1152
|
+
|
|
1153
|
+
// One target id for the entire progressive sequence. If the
|
|
1154
|
+
// caller supplied messageId, it is used; otherwise the first
|
|
1155
|
+
// generated message id becomes the target for all edits.
|
|
1156
|
+
let targetMessageId = options.messageId;
|
|
1157
|
+
let lastMessage;
|
|
1158
|
+
|
|
1159
|
+
const buildItemMessage = async (item) => {
|
|
1160
|
+
if (isInteractiveBuilder(item)) {
|
|
1161
|
+
item.setClient({ waUploadToServer });
|
|
1162
|
+
return await item.build(jid, { ...sendOptions, messageId: targetMessageId });
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
if (isAIRichBuilder(item)) {
|
|
1166
|
+
return await item.build(jid, { ...sendOptions, messageId: targetMessageId });
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Send Rich AI descriptors through the normal Rich AI
|
|
1170
|
+
// generator, but force the same message id.
|
|
1171
|
+
return await generateWAMessage(jid, { items: [item] }, {
|
|
1172
|
+
logger,
|
|
1173
|
+
userJid,
|
|
1174
|
+
upload: waUploadToServer,
|
|
1175
|
+
mediaCache: config.mediaCache,
|
|
1176
|
+
options: config.options,
|
|
1177
|
+
...sendOptions,
|
|
1178
|
+
messageId: targetMessageId || generateMessageIDV2(userJid)
|
|
1179
|
+
});
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
const isRichAiMessage = (msg) => !!(
|
|
1183
|
+
msg?.message?.botForwardedMessage?.message?.richResponseMessage ||
|
|
1184
|
+
msg?.message?.richResponseMessage
|
|
1185
|
+
);
|
|
1186
|
+
|
|
1187
|
+
const relayEdit = async (msg, targetId) => {
|
|
1188
|
+
const editedMessage = msg.message;
|
|
1189
|
+
const editMessage = await generateWAMessageFromContent(jid, {
|
|
1190
|
+
botForwardedMessage: { message: { protocolMessage: {
|
|
1191
|
+
key: { remoteJid: jid, fromMe: true, id: targetId },
|
|
1192
|
+
type: 14,
|
|
1193
|
+
editedMessage
|
|
1194
|
+
} } }
|
|
1195
|
+
}, { messageId: generateMessageIDV2(userJid) });
|
|
1196
|
+
|
|
1197
|
+
await relayMessage(jid, editMessage.message, {
|
|
1198
|
+
messageId: editMessage.key.id,
|
|
1199
|
+
additionalNodes: options.additionalNodes || []
|
|
1200
|
+
});
|
|
1201
|
+
return editMessage;
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
// Build a cumulative snapshot on every step. This is the
|
|
1205
|
+
// important part of buildDelay: each edit contains everything
|
|
1206
|
+
// built so far, rather than replacing the previous message
|
|
1207
|
+
// with only the newest item.
|
|
1208
|
+
const cumulativeItems = [];
|
|
1209
|
+
|
|
1210
|
+
for (let index = 0; index < items.length; index++) {
|
|
1211
|
+
if (index > 0 && hasDelay) {
|
|
1212
|
+
await delay(buildDelay);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
cumulativeItems.push(items[index]);
|
|
1216
|
+
|
|
1217
|
+
// AIRich instances represent an already assembled rich
|
|
1218
|
+
// response. For these, use their own build() directly.
|
|
1219
|
+
// For ordinary descriptors we rebuild the cumulative set.
|
|
1220
|
+
let msg;
|
|
1221
|
+
if (cumulativeItems.length === 1 && isAIRichBuilder(cumulativeItems[0])) {
|
|
1222
|
+
msg = await buildItemMessage(cumulativeItems[0]);
|
|
1223
|
+
} else if (cumulativeItems.every(isInteractiveBuilder) && cumulativeItems.length === 1) {
|
|
1224
|
+
msg = await buildItemMessage(cumulativeItems[0]);
|
|
1225
|
+
} else {
|
|
1226
|
+
const hasAirich = cumulativeItems.some(isAIRichBuilder);
|
|
1227
|
+
if (hasAirich) {
|
|
1228
|
+
// Mixed AIRich + descriptor items are flattened by
|
|
1229
|
+
// taking the AIRich message as the current snapshot
|
|
1230
|
+
// and are intentionally not sent as media.
|
|
1231
|
+
const ai = cumulativeItems.find(isAIRichBuilder);
|
|
1232
|
+
msg = await ai.build(jid, { ...sendOptions, messageId: targetMessageId });
|
|
1233
|
+
} else {
|
|
1234
|
+
msg = await generateWAMessage(jid, { items: cumulativeItems }, {
|
|
1235
|
+
logger,
|
|
1236
|
+
userJid,
|
|
1237
|
+
upload: waUploadToServer,
|
|
1238
|
+
mediaCache: config.mediaCache,
|
|
1239
|
+
options: config.options,
|
|
1240
|
+
...sendOptions,
|
|
1241
|
+
messageId: targetMessageId || generateMessageIDV2(userJid)
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
if (!targetMessageId) {
|
|
1247
|
+
targetMessageId = msg.key.id;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (index === 0) {
|
|
1251
|
+
const additionalNodes = isInteractiveBuilder(items[index])
|
|
1252
|
+
? [
|
|
1253
|
+
{
|
|
1254
|
+
tag: 'biz',
|
|
1255
|
+
attrs: {},
|
|
1256
|
+
content: [{
|
|
1257
|
+
tag: 'interactive',
|
|
1258
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
1259
|
+
content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
|
|
1260
|
+
}],
|
|
1261
|
+
},
|
|
1262
|
+
...(options.additionalNodes || []),
|
|
1263
|
+
]
|
|
1264
|
+
: (options.additionalNodes || []);
|
|
1265
|
+
|
|
1266
|
+
await relayMessage(jid, msg.message, {
|
|
1267
|
+
messageId: targetMessageId,
|
|
1268
|
+
additionalNodes,
|
|
1269
|
+
...sendOptions,
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
if (isRichAiMessage(msg) && options.bypassDownload !== false) {
|
|
1273
|
+
await relayEdit(msg, targetMessageId);
|
|
1274
|
+
}
|
|
1275
|
+
} else {
|
|
1276
|
+
await relayEdit(msg, targetMessageId);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
lastMessage = msg;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
if (lastMessage) {
|
|
1283
|
+
lastMessage.key.id = targetMessageId;
|
|
1147
1284
|
}
|
|
1148
|
-
return
|
|
1285
|
+
return lastMessage;
|
|
1149
1286
|
}
|
|
1150
1287
|
}
|
|
1151
1288
|
// Update rahmi's userJid in case it changed after login
|
package/lib/Utils/mbuilder.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const VERSION: string;
|
|
2
|
-
export declare class Button { constructor(client
|
|
3
|
-
export declare class ButtonV2 { constructor(client
|
|
4
|
-
export declare class Carousel { constructor(client
|
|
2
|
+
export declare class Button { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
|
|
3
|
+
export declare class ButtonV2 { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
|
|
4
|
+
export declare class Carousel { constructor(client?: any, options?: any); loadFrom(data: any): this; build(jid: string, options?: any): any; send(jid: string, options?: any): Promise<any>; [key: string]: any; }
|
|
5
5
|
export declare class AIRich {
|
|
6
6
|
constructor(client: any, options?: { dynamic?: boolean; unsupportedTypeAlert?: boolean });
|
|
7
7
|
loadFrom(msg: any): this;
|
|
@@ -38,6 +38,12 @@ export declare class AIRich {
|
|
|
38
38
|
export declare class Toolkit { [key: string]: any; }
|
|
39
39
|
export declare const build: {
|
|
40
40
|
AIRich: (client: any, options?: any) => AIRich;
|
|
41
|
+
button: (client?: any) => Button;
|
|
42
|
+
buttonV2: (client?: any) => ButtonV2;
|
|
43
|
+
carousel: (client?: any) => Carousel;
|
|
44
|
+
Button: (client?: any) => Button;
|
|
45
|
+
ButtonV2: (client?: any) => ButtonV2;
|
|
46
|
+
Carousel: (client?: any) => Carousel;
|
|
41
47
|
richText: (text: string) => any;
|
|
42
48
|
richFOAText: (text: string) => any;
|
|
43
49
|
richHtml: (html: string) => any;
|
package/lib/Utils/mbuilder.js
CHANGED
|
@@ -557,11 +557,8 @@ class BaseBuilder {
|
|
|
557
557
|
class Button extends BaseBuilder {
|
|
558
558
|
#client;
|
|
559
559
|
|
|
560
|
-
constructor(client) {
|
|
560
|
+
constructor(client = null) {
|
|
561
561
|
super();
|
|
562
|
-
if (!client) {
|
|
563
|
-
throw new Error('Socket is required');
|
|
564
|
-
}
|
|
565
562
|
this.#client = client;
|
|
566
563
|
|
|
567
564
|
this._buttons = [];
|
|
@@ -571,6 +568,11 @@ class Button extends BaseBuilder {
|
|
|
571
568
|
this._params = {};
|
|
572
569
|
}
|
|
573
570
|
|
|
571
|
+
setClient(client) {
|
|
572
|
+
this.#client = client;
|
|
573
|
+
return this;
|
|
574
|
+
}
|
|
575
|
+
|
|
574
576
|
loadFrom(msg) {
|
|
575
577
|
if (!msg) throw new Error('interactiveMessage needed');
|
|
576
578
|
if (!msg.interactiveMessage) throw new Error('interactiveMessage not found');
|
|
@@ -891,18 +893,19 @@ class Button extends BaseBuilder {
|
|
|
891
893
|
class ButtonV2 extends BaseBuilder {
|
|
892
894
|
#client;
|
|
893
895
|
|
|
894
|
-
constructor(client) {
|
|
896
|
+
constructor(client = null) {
|
|
895
897
|
super();
|
|
896
|
-
if (!client) {
|
|
897
|
-
throw new Error('Socket is required');
|
|
898
|
-
}
|
|
899
|
-
|
|
900
898
|
this.#client = client;
|
|
901
899
|
this._image;
|
|
902
900
|
this._data;
|
|
903
901
|
this._buttons = [];
|
|
904
902
|
}
|
|
905
903
|
|
|
904
|
+
setClient(client) {
|
|
905
|
+
this.#client = client;
|
|
906
|
+
return this;
|
|
907
|
+
}
|
|
908
|
+
|
|
906
909
|
loadFrom(msg) {
|
|
907
910
|
if (!msg) throw new Error('buttonsMessage needed');
|
|
908
911
|
if (!msg.buttonsMessage) throw new Error('buttonsMessage not found');
|
|
@@ -1059,16 +1062,17 @@ class ButtonV2 extends BaseBuilder {
|
|
|
1059
1062
|
class Carousel extends BaseBuilder {
|
|
1060
1063
|
#client;
|
|
1061
1064
|
|
|
1062
|
-
constructor(client) {
|
|
1065
|
+
constructor(client = null) {
|
|
1063
1066
|
super();
|
|
1064
|
-
if (!client) {
|
|
1065
|
-
throw new Error('Socket is required');
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
1067
|
this.#client = client;
|
|
1069
1068
|
this._cards = [];
|
|
1070
1069
|
}
|
|
1071
1070
|
|
|
1071
|
+
setClient(client) {
|
|
1072
|
+
this.#client = client;
|
|
1073
|
+
return this;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1072
1076
|
loadFrom(msg) {
|
|
1073
1077
|
if (!msg) throw new Error('interactiveMessage needed');
|
|
1074
1078
|
if (!msg.interactiveMessage) throw new Error('interactiveMessage not found');
|
|
@@ -3201,6 +3205,13 @@ class AIRich extends BaseBuilder {
|
|
|
3201
3205
|
*/
|
|
3202
3206
|
const build = {
|
|
3203
3207
|
AIRich: (client, options) => new AIRich(client, options),
|
|
3208
|
+
button: (client = null) => new Button(client),
|
|
3209
|
+
buttonV2: (client = null) => new ButtonV2(client),
|
|
3210
|
+
carousel: (client = null) => new Carousel(client),
|
|
3211
|
+
// Class aliases for developers who prefer constructor-style naming.
|
|
3212
|
+
Button: (client = null) => new Button(client),
|
|
3213
|
+
ButtonV2: (client = null) => new ButtonV2(client),
|
|
3214
|
+
Carousel: (client = null) => new Carousel(client),
|
|
3204
3215
|
richText: (text) => ({ richText: text }),
|
|
3205
3216
|
richFOAText: (text) => ({ richFOAText: text }),
|
|
3206
3217
|
richCode: (code, language = 'javascript') => ({ richCode: code, language }),
|
|
@@ -826,6 +826,34 @@ const normalizeTableInput = (t, fallbackTitle, fallbackNoHeading) => {
|
|
|
826
826
|
return { rows: [], title: fallbackTitle, noHeading: fallbackNoHeading };
|
|
827
827
|
};
|
|
828
828
|
|
|
829
|
+
/** Buat unified section untuk RICH CARD / ENTITY */
|
|
830
|
+
const makeRichCardSection = (data) => {
|
|
831
|
+
const item = data || {};
|
|
832
|
+
const thumbnailUrl = item.thumbnail_url ?? item.thumbnailUrl ?? item.thumbnail ?? '';
|
|
833
|
+
const profileUrl = item.profile_url ?? item.profileUrl ?? thumbnailUrl;
|
|
834
|
+
|
|
835
|
+
return {
|
|
836
|
+
view_model: {
|
|
837
|
+
primitive: {
|
|
838
|
+
__typename: 'GenAICompactEntityPrimitive',
|
|
839
|
+
title: item.title ?? '',
|
|
840
|
+
subtitle: item.subtitle ?? '',
|
|
841
|
+
secondary_subtitle: item.description ?? '',
|
|
842
|
+
entity_id: item.entity_id ?? item.entityId ?? '',
|
|
843
|
+
entity_url: item.entity_url ?? item.entityUrl ?? '',
|
|
844
|
+
entity_type: item.entity_type ?? 'PAGE',
|
|
845
|
+
action_type: item.action_type ?? 'FOLLOW',
|
|
846
|
+
is_verified: !!item.verification,
|
|
847
|
+
image: {
|
|
848
|
+
url: thumbnailUrl,
|
|
849
|
+
url_fallback: profileUrl
|
|
850
|
+
}
|
|
851
|
+
},
|
|
852
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
};
|
|
856
|
+
|
|
829
857
|
/* ─────────────────────────────────────────────────────────────
|
|
830
858
|
MAIN BUILDER — prepareRichResponseMessage
|
|
831
859
|
───────────────────────────────────────────────────────────── */
|
|
@@ -839,7 +867,7 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
839
867
|
map: mapContent, latex, contentItems,
|
|
840
868
|
// sub-types baru (prefixed 'rich' agar tidak konflik dengan media biasa)
|
|
841
869
|
richImage, richVideo, reels, source, richProduct, richPost, tip, suggest,
|
|
842
|
-
richWidget, widget, richFooterAction, footerAction, richMetadata, metadata, richFOAText, foaText, richHtml,
|
|
870
|
+
richWidget, widget, richFooterAction, footerAction, richMetadata, metadata, richFOAText, foaText, richHtml, richCard,
|
|
843
871
|
// opsi tambahan (belum ada di versi ponta.zip semula)
|
|
844
872
|
aiForwarded
|
|
845
873
|
} = content;
|
|
@@ -928,6 +956,7 @@ export const prepareRichResponseMessage = (content) => {
|
|
|
928
956
|
if (sub.footerAction != null) return push(null, makeFooterActionSection(sub.footerAction));
|
|
929
957
|
if (sub.metadata != null) { const built = makeMetadataSub(sub.metadata); return push(built.sub, built.section); }
|
|
930
958
|
if (sub.foaText != null) { const built = makeMetadataSub(sub.foaText, 'FOATextPrimitive'); return push(built.sub, built.section); }
|
|
959
|
+
if (sub.richCard != null) return push(null, makeRichCardSection(sub.richCard));
|
|
931
960
|
if (sub.richHtml != null) return push(null, makeHtmlSection(sub.richHtml));
|
|
932
961
|
// passthrough — kalau sudah bentuk proto submessage manual
|
|
933
962
|
return push(sub, buildUnifiedSection(sub));
|
|
@@ -1538,6 +1567,7 @@ const translateReadmeItem = (item) => {
|
|
|
1538
1567
|
if (item.richText != null) { out.text = item.richText; }
|
|
1539
1568
|
if (item.richFOAText != null) { out.foaText = item.richFOAText; }
|
|
1540
1569
|
if (item.richHtml != null) { out.richHtml = item.richHtml; }
|
|
1570
|
+
if (item.richCard != null) { out.richCard = item.richCard; }
|
|
1541
1571
|
if (item.richCode != null) { out.code = item.richCode; out.language = item.language; }
|
|
1542
1572
|
if (item.richTable != null) { out.table = item.richTable; }
|
|
1543
1573
|
if (item.richSource != null) { out.source = item.richSource; }
|
package/package.json
CHANGED