@nuiisweety/baileys 0.1.6 → 0.1.7
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 +238 -152
- package/README.md.bak +237 -151
- package/lib/Socket/messages-send.js +62 -0
- package/lib/Utils/rich-message-utils.js +378 -1
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinar
|
|
|
13
13
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
14
14
|
import { makeNewsletterSocket } from './newsletter.js';
|
|
15
15
|
import kikyy from './dugong.js';
|
|
16
|
+
import { generateTableContent, generateTableContentV2, generateListContent, generateCodeBlockContent, generateCodeBlockContentV2, generateLinkContent, generateLinkContentV2, generateRichMessageContent, generateUnifiedResponseContent, captureUnifiedResponse, generateLatexContent, generateLatexImageContent, generateLatexInlineImageContent } from '../Utils/rich-message-utils.js';
|
|
16
17
|
export const makeMessagesSocket = (config) => {
|
|
17
18
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
18
19
|
const sock = makeNewsletterSocket(config);
|
|
@@ -1329,6 +1330,67 @@ export const makeMessagesSocket = (config) => {
|
|
|
1329
1330
|
return fullMsg;
|
|
1330
1331
|
}
|
|
1331
1332
|
}
|
|
1333
|
+
sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
|
|
1334
|
+
const { message, messageId } = generateTableContent(title, headers, rows, quoted, options);
|
|
1335
|
+
await relayMessage(jid, message, { messageId });
|
|
1336
|
+
return { message, messageId };
|
|
1337
|
+
},
|
|
1338
|
+
sendTableV2: async (jid, table, quoted, options = {}) => {
|
|
1339
|
+
const { message, messageId } = generateTableContentV2(table, quoted, options);
|
|
1340
|
+
await relayMessage(jid, message, { messageId });
|
|
1341
|
+
return { message, messageId };
|
|
1342
|
+
},
|
|
1343
|
+
sendList: async (jid, title, items, quoted, options = {}) => {
|
|
1344
|
+
const { message, messageId } = generateListContent(title, items, quoted, options);
|
|
1345
|
+
await relayMessage(jid, message, { messageId });
|
|
1346
|
+
return { message, messageId };
|
|
1347
|
+
},
|
|
1348
|
+
sendCodeBlock: async (jid, code, quoted, options = {}) => {
|
|
1349
|
+
const { message, messageId } = generateCodeBlockContent(code, quoted, options);
|
|
1350
|
+
await relayMessage(jid, message, { messageId });
|
|
1351
|
+
return { message, messageId };
|
|
1352
|
+
},
|
|
1353
|
+
sendCodeBlockV2: async (jid, code, quoted, options = {}) => {
|
|
1354
|
+
const { message, messageId } = generateCodeBlockContentV2(code, quoted, options);
|
|
1355
|
+
await relayMessage(jid, message, { messageId });
|
|
1356
|
+
return { message, messageId };
|
|
1357
|
+
},
|
|
1358
|
+
sendLink: async (jid, text, links, quoted, options = {}) => {
|
|
1359
|
+
const { message, messageId } = generateLinkContent(text, links, quoted, options);
|
|
1360
|
+
await relayMessage(jid, message, { messageId });
|
|
1361
|
+
return { message, messageId };
|
|
1362
|
+
},
|
|
1363
|
+
sendLinkV2: async (jid, text, links, quoted, options = {}) => {
|
|
1364
|
+
const { message, messageId } = generateLinkContentV2(text, links, quoted, options);
|
|
1365
|
+
await relayMessage(jid, message, { messageId });
|
|
1366
|
+
return { message, messageId };
|
|
1367
|
+
},
|
|
1368
|
+
sendLatex: async (jid, quoted, options) => {
|
|
1369
|
+
const { message, messageId } = generateLatexContent(quoted, options);
|
|
1370
|
+
await relayMessage(jid, message, { messageId });
|
|
1371
|
+
return { message, messageId };
|
|
1372
|
+
},
|
|
1373
|
+
sendLatexImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1374
|
+
const { message, messageId } = await generateLatexImageContent(quoted, options, uploadFn, renderLatexToPng);
|
|
1375
|
+
await relayMessage(jid, message, { messageId });
|
|
1376
|
+
return { message, messageId };
|
|
1377
|
+
},
|
|
1378
|
+
sendLatexInlineImage: async (jid, quoted, options, renderLatexToPng, uploadFn) => {
|
|
1379
|
+
const { message, messageId } = await generateLatexInlineImageContent(quoted, options, uploadFn, renderLatexToPng);
|
|
1380
|
+
await relayMessage(jid, message, { messageId });
|
|
1381
|
+
return { message, messageId };
|
|
1382
|
+
},
|
|
1383
|
+
sendRichMessage: async (jid, submessages, quoted, options = {}) => {
|
|
1384
|
+
const { message, messageId } = generateRichMessageContent(submessages, quoted);
|
|
1385
|
+
await relayMessage(jid, message, { messageId });
|
|
1386
|
+
return { message, messageId };
|
|
1387
|
+
},
|
|
1388
|
+
sendUnifiedResponse: async (jid, quoted, captured) => {
|
|
1389
|
+
const { message, messageId } = generateUnifiedResponseContent(quoted, captured);
|
|
1390
|
+
await relayMessage(jid, message, { messageId });
|
|
1391
|
+
return { message, messageId };
|
|
1392
|
+
},
|
|
1393
|
+
captureUnifiedResponse,
|
|
1332
1394
|
};
|
|
1333
1395
|
};
|
|
1334
1396
|
//# sourceMappingURL=messages-send.js.map
|
|
@@ -3,7 +3,7 @@ import { DONATE_URL, LEXER_REGEX } from '../Defaults/index.js';
|
|
|
3
3
|
import { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
|
|
4
4
|
import { CodeHighlightType, RichSubMessageType } from '../Types/RichType.js';
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
|
-
import { unixTimestampSeconds } from './generics.js';
|
|
6
|
+
import { unixTimestampSeconds, generateMessageIDV2 } from './generics.js';
|
|
7
7
|
|
|
8
8
|
const NOOP = new Set([]);
|
|
9
9
|
|
|
@@ -943,4 +943,381 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
|
|
|
943
943
|
message: { richResponseMessage }
|
|
944
944
|
}
|
|
945
945
|
});
|
|
946
|
+
|
|
947
|
+
/* ─────────────────────────────────────────────────────────────
|
|
948
|
+
STANDALONE GENERATORS (kompatibel dengan baileys upstream)
|
|
949
|
+
Semua fungsi di bawah ini di-port dari baileys-main/src/Utils/rich-messages.js
|
|
950
|
+
agar API nuii 100% kompatibel dengan baileys — termasuk sendTable, sendLatex, dll.
|
|
951
|
+
───────────────────────────────────────────────────────────── */
|
|
952
|
+
|
|
953
|
+
/* helper: bangun contextInfo dari quoted */
|
|
954
|
+
const buildRichContextInfo = (quoted) => {
|
|
955
|
+
const ctxInfo = {
|
|
956
|
+
isForwarded: true,
|
|
957
|
+
forwardingScore: 1,
|
|
958
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
959
|
+
forwardOrigin: 4,
|
|
960
|
+
};
|
|
961
|
+
if (quoted?.key) {
|
|
962
|
+
ctxInfo.stanzaId = quoted.key.id;
|
|
963
|
+
ctxInfo.participant = quoted.key.participant || quoted.sender || quoted.key.remoteJid;
|
|
964
|
+
ctxInfo.quotedMessage = quoted.message;
|
|
965
|
+
}
|
|
966
|
+
return ctxInfo;
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
/* helper: wrap submessages + contextInfo ke botForwardedMessage (format lama/V1) */
|
|
970
|
+
const buildBotForwardedMessage = (submessages, contextInfo, unifiedResponse) => {
|
|
971
|
+
const richResponse = { messageType: 1, submessages, contextInfo };
|
|
972
|
+
if (unifiedResponse) richResponse.unifiedResponse = unifiedResponse;
|
|
973
|
+
return { botForwardedMessage: { message: { richResponseMessage: richResponse } } };
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
/* helper: wrap proto AIRichResponseMessage ke botForwardedMessage dengan messageContextInfo */
|
|
977
|
+
const _wrapProtoToResult = (submessages, quoted) => {
|
|
978
|
+
const unified = toUnified(submessages);
|
|
979
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
980
|
+
submessages,
|
|
981
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
982
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(unified), 'utf-8') },
|
|
983
|
+
contextInfo: buildRichContextInfo(quoted),
|
|
984
|
+
});
|
|
985
|
+
return { message: wrapToBotForwardedMessage(richResponseMessage), messageId: generateMessageIDV2() };
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
// ── Table ──────────────────────────────────────────────────
|
|
989
|
+
|
|
990
|
+
export const generateTableContent = (title, headers, rows, quoted, options = {}) => {
|
|
991
|
+
const { footer, headerText } = options;
|
|
992
|
+
const tableRows = [{ items: headers, isHeading: true }, ...rows.map(row => ({ items: row.map(String) }))];
|
|
993
|
+
const subs = [];
|
|
994
|
+
if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
995
|
+
subs.push({ messageType: RichSubMessageType.TABLE, tableMetadata: { title, rows: tableRows } });
|
|
996
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
997
|
+
return _wrapProtoToResult(subs, quoted);
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
export const generateListContent = (title, items, quoted, options = {}) => {
|
|
1001
|
+
const { footer, headerText } = options;
|
|
1002
|
+
const tableRows = items.map(item => ({ items: Array.isArray(item) ? item.map(String) : [String(item)] }));
|
|
1003
|
+
const subs = [];
|
|
1004
|
+
if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
1005
|
+
subs.push({ messageType: RichSubMessageType.TABLE, tableMetadata: { title, rows: tableRows } });
|
|
1006
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
1007
|
+
return _wrapProtoToResult(subs, quoted);
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
export const toTableMetadataV2 = (arr) => {
|
|
1011
|
+
if (!Array.isArray(arr) || arr.length === 0) throw new Error('Input must be a non-empty array');
|
|
1012
|
+
const [title, headerStr, ...rest] = arr;
|
|
1013
|
+
const splitCols = (str) => typeof str !== 'string' ? [] : str.includes('|') ? str.split('|').map(s => s.trim()) : str.split(',').map(s => s.trim());
|
|
1014
|
+
const splitRows = (str) => typeof str !== 'string' ? [] : str.split(';;').map(row => splitCols(row));
|
|
1015
|
+
const header = splitCols(headerStr);
|
|
1016
|
+
const parsedRows = rest.flatMap(splitRows);
|
|
1017
|
+
const maxLen = Math.max(header.length, ...parsedRows.map(r => r.length));
|
|
1018
|
+
const unified_rows = [
|
|
1019
|
+
{ is_header: true, cells: [...header, ...Array(maxLen - header.length).fill('')] },
|
|
1020
|
+
...parsedRows.map(cells => ({ is_header: false, cells: [...cells, ...Array(maxLen - cells.length).fill('')] }))
|
|
1021
|
+
];
|
|
1022
|
+
const rows = unified_rows.map(r => ({ items: r.cells, ...(r.is_header ? { isHeading: true } : {}) }));
|
|
1023
|
+
return { title, rows, unified_rows };
|
|
1024
|
+
};
|
|
1025
|
+
|
|
1026
|
+
export const generateTableContentV2 = (table, quoted, options = {}) => {
|
|
1027
|
+
const { title, footer, headerText, text } = options;
|
|
1028
|
+
const { unified_rows } = toTableMetadataV2(table);
|
|
1029
|
+
const subs = [];
|
|
1030
|
+
const sections = [];
|
|
1031
|
+
if (headerText || title) sections.push({ view_model: { primitive: { text: headerText || title, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1032
|
+
if (text) sections.push({ view_model: { primitive: { text, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1033
|
+
sections.push({ view_model: { primitive: { rows: unified_rows, __typename: 'GenATableUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1034
|
+
if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1035
|
+
// using randomUUID and randomBytes from top-level import
|
|
1036
|
+
const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
|
|
1037
|
+
const ctxInfo = buildRichContextInfo(quoted);
|
|
1038
|
+
ctxInfo.forwardingScore = 2;
|
|
1039
|
+
ctxInfo.botMessageSharingInfo = { botEntryPointOrigin: 1, forwardScore: 2 };
|
|
1040
|
+
const content = {
|
|
1041
|
+
messageContextInfo: { threadId: [], deviceListMetadata: { senderKeyIndexes: [], recipientKeyIndexes: [], recipientKeyHash: '', recipientTimestamp: Math.floor(Date.now() / 1000) }, deviceListMetadataVersion: 2, messageSecret: randomBytes(32) },
|
|
1042
|
+
botForwardedMessage: { message: { richResponseMessage: { submessages: subs, messageType: 1, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } }
|
|
1043
|
+
};
|
|
1044
|
+
return { message: content, messageId: generateMessageIDV2() };
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
// ── Code Block ────────────────────────────────────────────
|
|
1048
|
+
|
|
1049
|
+
export const generateCodeBlockContent = (code, quoted, options = {}) => {
|
|
1050
|
+
const { title, footer, language = 'javascript' } = options;
|
|
1051
|
+
const subs = [];
|
|
1052
|
+
if (title) subs.push({ messageType: RichSubMessageType.TEXT, messageText: title });
|
|
1053
|
+
subs.push({ messageType: RichSubMessageType.CODE, codeMetadata: { codeLanguage: language, codeBlocks: tokenizeCode(code, language) } });
|
|
1054
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
1055
|
+
return _wrapProtoToResult(subs, quoted);
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
export const generateCodeBlockContentV2 = (code, quoted, options = {}) => {
|
|
1059
|
+
const { title, footer, language = 'javascript', text } = options;
|
|
1060
|
+
const { unified_codeBlock } = tokenizeCodeV2(code, language);
|
|
1061
|
+
const sections = [];
|
|
1062
|
+
if (text) sections.push({ view_model: { primitive: { text, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1063
|
+
sections.push({ view_model: { primitive: { language, code_blocks: unified_codeBlock, __typename: 'GenAICodeUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1064
|
+
if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1065
|
+
// using randomUUID and randomBytes from top-level import
|
|
1066
|
+
const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
|
|
1067
|
+
const ctxInfo = buildRichContextInfo(quoted);
|
|
1068
|
+
ctxInfo.forwardingScore = 2;
|
|
1069
|
+
ctxInfo.mentionedJid = [];
|
|
1070
|
+
ctxInfo.groupMentions = [];
|
|
1071
|
+
ctxInfo.statusAttributions = [];
|
|
1072
|
+
ctxInfo.botMessageSharingInfo = { botEntryPointOrigin: 1, forwardScore: 2 };
|
|
1073
|
+
const content = {
|
|
1074
|
+
messageContextInfo: { threadId: [], deviceListMetadata: { senderKeyIndexes: [], recipientKeyIndexes: [], recipientKeyHash: '', recipientTimestamp: Math.floor(Date.now() / 1000) }, deviceListMetadataVersion: 2, messageSecret: randomBytes(32) },
|
|
1075
|
+
botForwardedMessage: { message: { richResponseMessage: { submessages: [], messageType: 1, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } }
|
|
1076
|
+
};
|
|
1077
|
+
return { message: content, messageId: generateMessageIDV2() };
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// ── Rich Message (generic) ────────────────────────────────
|
|
1081
|
+
|
|
1082
|
+
export const generateRichMessageContent = (submessages, quoted) => {
|
|
1083
|
+
return _wrapProtoToResult(submessages, quoted);
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
export const generateUnifiedResponseContent = (quoted, captured) => {
|
|
1087
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
1088
|
+
submessages: captured.submessages,
|
|
1089
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
1090
|
+
unifiedResponse: captured.unifiedResponse,
|
|
1091
|
+
contextInfo: buildRichContextInfo(quoted),
|
|
1092
|
+
});
|
|
1093
|
+
return { message: wrapToBotForwardedMessage(richResponseMessage), messageId: generateMessageIDV2() };
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
export const captureUnifiedResponse = (msg) => {
|
|
1097
|
+
const botFwd = msg?.botForwardedMessage?.message;
|
|
1098
|
+
if (!botFwd) return null;
|
|
1099
|
+
const rich = botFwd.richResponseMessage;
|
|
1100
|
+
if (!rich?.unifiedResponse?.data) return null;
|
|
1101
|
+
return { unifiedResponse: { data: rich.unifiedResponse.data }, submessages: rich.submessages || [], contextInfo: rich.contextInfo || {} };
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
// ── Link ──────────────────────────────────────────────────
|
|
1105
|
+
|
|
1106
|
+
export const generateLinkContent = (text, links, quoted, options = {}) => {
|
|
1107
|
+
const { footer, botJid = '867051314767696@bot', forwardingScore = 3, citations = [], proofs = [] } = options;
|
|
1108
|
+
const subs = [];
|
|
1109
|
+
const fullText = footer ? `${text}${footer}` : text;
|
|
1110
|
+
subs.push({ messageType: RichSubMessageType.TEXT, messageText: fullText });
|
|
1111
|
+
const sections = [];
|
|
1112
|
+
const inlineEntities = links.map((link, i) => {
|
|
1113
|
+
const url = typeof link === 'string' ? link : link.url;
|
|
1114
|
+
const displayName = typeof link === 'object' && link.displayName ? link.displayName : citations[i]?.sourceTitle || `Link ${i + 1}`;
|
|
1115
|
+
return { key: `IE_${i}`, metadata: { display_name: displayName, is_trusted: false, url, __typename: 'GenAIInlineLinkItem' } };
|
|
1116
|
+
});
|
|
1117
|
+
sections.push({ view_model: { primitive: { text, inline_entities: inlineEntities, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1118
|
+
if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1119
|
+
// using randomUUID and randomBytes from top-level import
|
|
1120
|
+
const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
|
|
1121
|
+
const ctxInfo = buildRichContextInfo(quoted);
|
|
1122
|
+
ctxInfo.forwardingScore = forwardingScore;
|
|
1123
|
+
ctxInfo.forwardedAiBotMessageInfo = { botJid };
|
|
1124
|
+
ctxInfo.botMessageSharingInfo = { forwardScore: forwardingScore };
|
|
1125
|
+
const messageContextInfo = { messageSecret: randomBytes(32) };
|
|
1126
|
+
if (citations.length > 0 || proofs.length > 0) {
|
|
1127
|
+
const botMetadata = {};
|
|
1128
|
+
if (citations.length > 0) botMetadata.richResponseSourcesMetadata = { sources: citations.map((c, i) => ({ provider: 1, thumbnailCdnUrl: '', sourceProviderUrl: typeof links[i] === 'string' ? links[i] : links[i]?.url || '', sourceQuery: c.sourceQuery || '', faviconCdnUrl: c.faviconCdnUrl || '', citationNumber: c.citationNumber ?? i + 1, sourceTitle: c.sourceTitle || '' })) };
|
|
1129
|
+
if (proofs.length > 0) botMetadata.verificationMetadata = { proofs: proofs.map(p => ({ version: p.version || 1, useCase: p.useCase || 1, signature: p.signature || '', certificateChain: p.certificateChain || [] })) };
|
|
1130
|
+
messageContextInfo.botMetadata = botMetadata;
|
|
1131
|
+
}
|
|
1132
|
+
const content = { messageContextInfo, botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: subs, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } } };
|
|
1133
|
+
return { message: content, messageId: generateMessageIDV2() };
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
export const generateLinkContentV2 = (text, links, quoted, options = {}) => {
|
|
1137
|
+
const { footer, searchEngine = 'MAME' } = options;
|
|
1138
|
+
const subs = [];
|
|
1139
|
+
const fullText = footer ? `${text}${footer}` : text;
|
|
1140
|
+
subs.push({ messageType: RichSubMessageType.TEXT, messageText: fullText });
|
|
1141
|
+
const sections = [];
|
|
1142
|
+
const inlineEntities = links.map((link, i) => {
|
|
1143
|
+
const url = typeof link === 'string' ? link : link.url;
|
|
1144
|
+
const displayName = typeof link === 'object' && link.displayName ? link.displayName : `Link ${i + 1}`;
|
|
1145
|
+
const sourceDisplayName = typeof link === 'object' && link.sourceDisplayName ? link.sourceDisplayName : `Source ${i + 1}`;
|
|
1146
|
+
const sourceSubtitle = typeof link === 'object' && link.sourceSubtitle ? link.sourceSubtitle : '';
|
|
1147
|
+
return { key: `IE_${i}`, metadata: { reference_id: i + 1, reference_url: url, reference_title: displayName, reference_display_name: displayName, sources: [{ source_type: 'THIRD_PARTY', source_display_name: sourceDisplayName, source_subtitle: sourceSubtitle, source_url: url }], __typename: 'GenAISearchCitationItem' } };
|
|
1148
|
+
});
|
|
1149
|
+
sections.push({ view_model: { primitive: { text, inline_entities: inlineEntities, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1150
|
+
const searchSources = links.map((link, i) => {
|
|
1151
|
+
const url = typeof link === 'string' ? link : link.url;
|
|
1152
|
+
const sourceDisplayName = typeof link === 'object' && link.sourceDisplayName ? link.sourceDisplayName : `Source ${i + 1}`;
|
|
1153
|
+
const sourceSubtitle = typeof link === 'object' && link.sourceSubtitle ? link.sourceSubtitle : '';
|
|
1154
|
+
return { source_type: 'THIRD_PARTY', source_display_name: sourceDisplayName, source_subtitle: sourceSubtitle, source_url: url };
|
|
1155
|
+
});
|
|
1156
|
+
sections.push({ view_model: { primitive: { sources: searchSources, search_engine: searchEngine, __typename: 'GenAISearchResultPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1157
|
+
if (footer) sections.push({ view_model: { primitive: { text: footer, __typename: 'GenAIMarkdownTextUXPrimitive' }, __typename: 'GenAISingleLayoutViewModel' } });
|
|
1158
|
+
// using randomUUID and randomBytes from top-level import
|
|
1159
|
+
const base64Data = Buffer.from(JSON.stringify({ response_id: randomUUID(), sections })).toString('base64');
|
|
1160
|
+
const ctxInfo = { isForwarded: true, forwardOrigin: 4 };
|
|
1161
|
+
if (quoted?.key) { ctxInfo.participant = quoted.key.participant || quoted.sender || quoted.key.remoteJid; ctxInfo.quotedMessage = quoted.message; }
|
|
1162
|
+
const content = { messageContextInfo: { threadId: [], messageSecret: randomBytes(32) }, botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: subs, unifiedResponse: { data: base64Data }, contextInfo: ctxInfo } } } };
|
|
1163
|
+
return { message: content, messageId: generateMessageIDV2() };
|
|
1164
|
+
};
|
|
1165
|
+
|
|
1166
|
+
// ── LaTeX (3 varian, port dari baileys) ──────────────────
|
|
1167
|
+
|
|
1168
|
+
/**
|
|
1169
|
+
* generateLatexContent — kirim LaTeX dengan URL gambar yang sudah ada (pre-rendered).
|
|
1170
|
+
* Jika `expr.url` tidak diisi, otomatis di-generate via buildLatexUrl (codecogs).
|
|
1171
|
+
*
|
|
1172
|
+
* @param {object} quoted - pesan yang di-quote (boleh null)
|
|
1173
|
+
* @param {object} options - { text, expressions, headerText, footer }
|
|
1174
|
+
* expressions: Array<{ latexExpression, url?, width?, height?,
|
|
1175
|
+
* fontHeight?, imageTopPadding?, imageLeadingPadding?,
|
|
1176
|
+
* imageBottomPadding?, imageTrailingPadding? }>
|
|
1177
|
+
*/
|
|
1178
|
+
export const generateLatexContent = (quoted, options) => {
|
|
1179
|
+
const { text, expressions, headerText, footer } = options;
|
|
1180
|
+
const subs = [];
|
|
1181
|
+
if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
1182
|
+
const latexExpressions = expressions.map((expr) => {
|
|
1183
|
+
const entry = {
|
|
1184
|
+
latexExpression: expr.latexExpression,
|
|
1185
|
+
url: expr.url || buildLatexUrl(expr.latexExpression),
|
|
1186
|
+
width: expr.width ?? 120,
|
|
1187
|
+
height: expr.height ?? 40,
|
|
1188
|
+
};
|
|
1189
|
+
if (expr.fontHeight !== undefined) entry.fontHeight = expr.fontHeight;
|
|
1190
|
+
if (expr.imageTopPadding !== undefined) entry.imageTopPadding = expr.imageTopPadding;
|
|
1191
|
+
if (expr.imageLeadingPadding !== undefined) entry.imageLeadingPadding = expr.imageLeadingPadding;
|
|
1192
|
+
if (expr.imageBottomPadding !== undefined) entry.imageBottomPadding = expr.imageBottomPadding;
|
|
1193
|
+
if (expr.imageTrailingPadding !== undefined) entry.imageTrailingPadding = expr.imageTrailingPadding;
|
|
1194
|
+
return entry;
|
|
1195
|
+
});
|
|
1196
|
+
subs.push({ messageType: RichSubMessageType.LATEX, latexMetadata: { text: text || '', expressions: latexExpressions } });
|
|
1197
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
1198
|
+
return _wrapProtoToResult(subs, quoted);
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* generateLatexImageContent — render LaTeX ke PNG via renderLatexToPng,
|
|
1203
|
+
* upload via uploadFn, kirim sebagai LaTeX message dengan URL hasil upload.
|
|
1204
|
+
*
|
|
1205
|
+
* @param {object} quoted - pesan yang di-quote (boleh null)
|
|
1206
|
+
* @param {object} options - { text, expressions, headerText, footer }
|
|
1207
|
+
* @param {Function} uploadFn - async (buffer, type) => { url, directPath }
|
|
1208
|
+
* @param {Function} renderLatexToPng - async (latexExpression) => { buffer, width, height }
|
|
1209
|
+
*/
|
|
1210
|
+
export const generateLatexImageContent = async (quoted, options, uploadFn, renderLatexToPng) => {
|
|
1211
|
+
const { text, expressions, headerText, footer } = options;
|
|
1212
|
+
const subs = [];
|
|
1213
|
+
if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
1214
|
+
const latexExpressions = await Promise.all(
|
|
1215
|
+
expressions.map(async (expr) => {
|
|
1216
|
+
const { buffer, width, height } = await renderLatexToPng(expr.latexExpression);
|
|
1217
|
+
const uploadResult = await uploadFn(buffer, 'image');
|
|
1218
|
+
const imageUrl = uploadResult.url || uploadResult.directPath;
|
|
1219
|
+
return { latexExpression: expr.latexExpression, url: imageUrl, width, height };
|
|
1220
|
+
}),
|
|
1221
|
+
);
|
|
1222
|
+
subs.push({ messageType: RichSubMessageType.LATEX, latexMetadata: { text: text || '', expressions: latexExpressions } });
|
|
1223
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
1224
|
+
return _wrapProtoToResult(subs, quoted);
|
|
1225
|
+
};
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* generateLatexInlineImageContent — render LaTeX ke PNG, upload, kirim sebagai
|
|
1229
|
+
* deretan INLINE_IMAGE (satu per expression). Fallback untuk klien tanpa LaTeX native.
|
|
1230
|
+
*
|
|
1231
|
+
* @param {object} quoted - pesan yang di-quote (boleh null)
|
|
1232
|
+
* @param {object} options - { text, expressions, headerText, footer }
|
|
1233
|
+
* @param {Function} uploadFn - async (buffer, type) => { url, directPath }
|
|
1234
|
+
* @param {Function} renderLatexToPng - async (latexExpression) => { buffer, width, height }
|
|
1235
|
+
*/
|
|
1236
|
+
export const generateLatexInlineImageContent = async (quoted, options, uploadFn, renderLatexToPng) => {
|
|
1237
|
+
const { text, expressions, headerText, footer } = options;
|
|
1238
|
+
const subs = [];
|
|
1239
|
+
if (headerText) subs.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
1240
|
+
if (text) subs.push({ messageType: RichSubMessageType.TEXT, messageText: text });
|
|
1241
|
+
for (const expr of expressions) {
|
|
1242
|
+
const { buffer, width, height } = await renderLatexToPng(expr.latexExpression);
|
|
1243
|
+
const uploadResult = await uploadFn(buffer, 'image');
|
|
1244
|
+
const imageUrl = uploadResult.url || uploadResult.directPath;
|
|
1245
|
+
subs.push({
|
|
1246
|
+
messageType: RichSubMessageType.INLINE_IMAGE,
|
|
1247
|
+
imageMetadata: {
|
|
1248
|
+
imageUrl: { imagePreviewUrl: imageUrl, imageHighResUrl: imageUrl },
|
|
1249
|
+
imageText: expr.latexExpression,
|
|
1250
|
+
alignment: 2,
|
|
1251
|
+
},
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
if (footer) subs.push({ messageType: RichSubMessageType.TEXT, messageText: footer });
|
|
1255
|
+
return _wrapProtoToResult(subs, quoted);
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
// ── tokenizeCodeV2 (dipakai oleh generateCodeBlockContentV2) ─
|
|
1259
|
+
|
|
1260
|
+
export const tokenizeCodeV2 = (code, language = 'javascript') => {
|
|
1261
|
+
const keywords = LANGUAGE_KEYWORDS[language] || LANGUAGE_KEYWORDS['javascript'] || new Set();
|
|
1262
|
+
const tokens = [];
|
|
1263
|
+
let i = 0;
|
|
1264
|
+
const n = code.length;
|
|
1265
|
+
const push = (codeContent, highlightType) => {
|
|
1266
|
+
if (!codeContent) return;
|
|
1267
|
+
const last = tokens[tokens.length - 1];
|
|
1268
|
+
if (last && last.highlightType === highlightType) last.codeContent += codeContent;
|
|
1269
|
+
else tokens.push({ codeContent, highlightType });
|
|
1270
|
+
};
|
|
1271
|
+
const isWordStart = (c) => /[a-zA-Z_$]/.test(c);
|
|
1272
|
+
const isWord = (c) => /[a-zA-Z0-9_$]/.test(c);
|
|
1273
|
+
const isNum = (c) => /[0-9]/.test(c);
|
|
1274
|
+
const HIGHLIGHT_TYPE_MAP = { 0: 'DEFAULT', 1: 'KEYWORD', 2: 'METHOD', 3: 'STR', 4: 'NUMBER', 5: 'COMMENT' };
|
|
1275
|
+
const isPyBash = ['python','py','bash','sh','shell'].includes(language);
|
|
1276
|
+
while (i < n) {
|
|
1277
|
+
const c = code[i];
|
|
1278
|
+
if (/\s/.test(c)) {
|
|
1279
|
+
let s = i; while (i < n && /\s/.test(code[i])) i++;
|
|
1280
|
+
push(code.slice(s, i), 0); continue;
|
|
1281
|
+
}
|
|
1282
|
+
if (c === '/' && code[i + 1] === '/') {
|
|
1283
|
+
let s = i; i += 2; while (i < n && code[i] !== '\n') i++;
|
|
1284
|
+
push(code.slice(s, i), 5); continue;
|
|
1285
|
+
}
|
|
1286
|
+
if (c === '/' && code[i + 1] === '*') {
|
|
1287
|
+
let s = i; i += 2;
|
|
1288
|
+
while (i < n - 1 && !(code[i] === '*' && code[i + 1] === '/')) i++;
|
|
1289
|
+
i += 2; push(code.slice(s, i), 5); continue;
|
|
1290
|
+
}
|
|
1291
|
+
if (c === '#' && isPyBash) {
|
|
1292
|
+
let s = i; i++; while (i < n && code[i] !== '\n') i++;
|
|
1293
|
+
push(code.slice(s, i), 5); continue;
|
|
1294
|
+
}
|
|
1295
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
1296
|
+
let s = i; const q = c; i++;
|
|
1297
|
+
while (i < n) { if (code[i] === '\\' && i + 1 < n) i += 2; else if (code[i] === q) { i++; break; } else i++; }
|
|
1298
|
+
push(code.slice(s, i), 3); continue;
|
|
1299
|
+
}
|
|
1300
|
+
if (isNum(c)) {
|
|
1301
|
+
let s = i; while (i < n && /[0-9.xXa-fA-FeEbBoO_]/.test(code[i])) i++;
|
|
1302
|
+
push(code.slice(s, i), 4); continue;
|
|
1303
|
+
}
|
|
1304
|
+
if (isWordStart(c)) {
|
|
1305
|
+
let s = i; while (i < n && isWord(code[i])) i++;
|
|
1306
|
+
const word = code.slice(s, i);
|
|
1307
|
+
let type = 0;
|
|
1308
|
+
if (keywords.has(word)) type = 1;
|
|
1309
|
+
else { let j = i; while (j < n && /\s/.test(code[j])) j++; if (code[j] === '(') type = 2; }
|
|
1310
|
+
push(word, type); continue;
|
|
1311
|
+
}
|
|
1312
|
+
push(c, 0); i++;
|
|
1313
|
+
}
|
|
1314
|
+
return {
|
|
1315
|
+
codeBlock: tokens,
|
|
1316
|
+
unified_codeBlock: tokens.map(t => ({ content: t.codeContent, type: HIGHLIGHT_TYPE_MAP[t.highlightType] || 'DEFAULT' }))
|
|
1317
|
+
};
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
/* Re-export LANGUAGE_KEYWORDS dari WABinary/constants.js agar kompatibel dengan baileys export */
|
|
1321
|
+
export { LANGUAGE_KEYWORDS } from '../WABinary/constants.js';
|
|
1322
|
+
|
|
946
1323
|
//# sourceMappingURL=rich-message-utils.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuiisweety/baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7",
|
|
5
5
|
"description": "A WebSockets library for interacting with WhatsApp Web — forked STRICTLY from @whiskeysockets/baileys only, NOT from any other baileys fork. Modified by NuiiSweety.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|