@langitdeveloper/baileys 2.2.0 → 2.2.2
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/lib/Socket/business.js +1 -1
- package/lib/Socket/messages-recv.js +1 -1
- package/lib/Socket/messages-send.js +22 -11
- package/lib/Socket/socket.js +3 -1
- package/lib/Utils/bot-toolkit.js +74 -9
- package/lib/Utils/decode-wa-message.js +1 -1
- package/lib/Utils/generics.js +1 -1
- package/lib/Utils/messages.js +1 -366
- package/lib/Utils/use-multi-file-auth-state.js +6 -1
- package/package.json +1 -1
package/lib/Socket/business.js
CHANGED
|
@@ -341,19 +341,30 @@ const makeMessagesSocket = (config) => {
|
|
|
341
341
|
meId,
|
|
342
342
|
});
|
|
343
343
|
const senderKeyJids = [];
|
|
344
|
-
const
|
|
345
|
-
const
|
|
344
|
+
const myRecipients = [];
|
|
345
|
+
const peerRecipients = [];
|
|
346
|
+
const { user: selfPnUser } = WABinary_1.jidDecode(meId);
|
|
347
|
+
const { user: selfLidUser } = meLid ? WABinary_1.jidDecode(meLid) : { user: null };
|
|
346
348
|
for (const { user, device } of devices) {
|
|
347
|
-
const
|
|
348
|
-
//
|
|
349
|
-
const
|
|
350
|
-
if (
|
|
351
|
-
logger.debug({
|
|
349
|
+
const targetJid = WABinary_1.jidEncode(user, (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) === 'lid' ? 'lid' : 's.whatsapp.net', device);
|
|
350
|
+
// a device never needs its own sender-key re-sent to it - it already has it
|
|
351
|
+
const isSendingDeviceItself = targetJid === meId || (meLid && targetJid === meLid);
|
|
352
|
+
if (isSendingDeviceItself) {
|
|
353
|
+
logger.debug({ targetJid, meId, meLid }, 'skipping sender\'s own device for sender-key distribution');
|
|
352
354
|
continue;
|
|
353
355
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
356
|
+
const belongsToSelf = user === selfPnUser || user === selfLidUser;
|
|
357
|
+
// when this call targets one specific participant (a retry resend),
|
|
358
|
+
// our own other devices don't need it - they're already in sync via
|
|
359
|
+
// the normal multi-device session, only the actual peer does
|
|
360
|
+
const isSkippedAsOwnDeviceDuringTargetedResend = !!participant && !(0, WABinary_1.isJidGroup)(targetJid) && !isStatus && belongsToSelf;
|
|
361
|
+
if (isSkippedAsOwnDeviceDuringTargetedResend) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
(belongsToSelf ? myRecipients : peerRecipients).push(targetJid);
|
|
365
|
+
if (!senderKeyMap[targetJid] || !!participant) {
|
|
366
|
+
senderKeyJids.push(targetJid);
|
|
367
|
+
senderKeyMap[targetJid] = true;
|
|
357
368
|
}
|
|
358
369
|
}
|
|
359
370
|
if (senderKeyJids.length) {
|
|
@@ -837,4 +848,4 @@ const makeMessagesSocket = (config) => {
|
|
|
837
848
|
}
|
|
838
849
|
}
|
|
839
850
|
};
|
|
840
|
-
exports.makeMessagesSocket = makeMessagesSocket;
|
|
851
|
+
exports.makeMessagesSocket = makeMessagesSocket;
|
package/lib/Socket/socket.js
CHANGED
|
@@ -690,7 +690,7 @@ const makeSocket = (config) => {
|
|
|
690
690
|
if (printQRInTerminal) {
|
|
691
691
|
(0, Utils_1.printQRIfNecessaryListener)(ev, logger);
|
|
692
692
|
}
|
|
693
|
-
|
|
693
|
+
const baseSocket = {
|
|
694
694
|
type: 'md',
|
|
695
695
|
ws,
|
|
696
696
|
ev,
|
|
@@ -718,6 +718,8 @@ const makeSocket = (config) => {
|
|
|
718
718
|
waitForConnectionUpdate: (0, Utils_1.bindWaitForConnectionUpdate)(ev),
|
|
719
719
|
sendWAMBuffer,
|
|
720
720
|
};
|
|
721
|
+
Object.assign(baseSocket, (0, Utils_1.makeBotToolkit)(baseSocket, logger));
|
|
722
|
+
return baseSocket;
|
|
721
723
|
};
|
|
722
724
|
exports.makeSocket = makeSocket;
|
|
723
725
|
/**
|
package/lib/Utils/bot-toolkit.js
CHANGED
|
@@ -27,6 +27,77 @@ const makeBotToolkit = (conn, logger) => {
|
|
|
27
27
|
const groupMetaCache = new Map(); // jid -> { data, fetchedAt }
|
|
28
28
|
const GROUP_META_TTL_MS = 60 * 1000;
|
|
29
29
|
return {
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a user is an admin/superadmin in a group, using the
|
|
32
|
+
* cached metadata getter above so repeated checks (every message in
|
|
33
|
+
* a busy group) don't keep re-fetching from WA.
|
|
34
|
+
*/
|
|
35
|
+
async isGroupAdmin(groupJid, userJid) {
|
|
36
|
+
const meta = await this.getCachedGroupMetadata(groupJid);
|
|
37
|
+
const participant = meta?.participants?.find((p) => p.id === userJid || p.jid === userJid);
|
|
38
|
+
return participant?.admin === 'admin' || participant?.admin === 'superadmin';
|
|
39
|
+
},
|
|
40
|
+
/**
|
|
41
|
+
* Splits long text into WhatsApp-safe chunks and sends them one
|
|
42
|
+
* after another (with a small delay), so a long AI response or log
|
|
43
|
+
* dump doesn't get truncated or rejected for being too long.
|
|
44
|
+
*/
|
|
45
|
+
async sendChunked(jid, text, options = {}, maxLen = 4000, delayMs = 800) {
|
|
46
|
+
if (!text || text.length <= maxLen) {
|
|
47
|
+
return [await conn.sendMessage(jid, { text, ...options })];
|
|
48
|
+
}
|
|
49
|
+
const chunks = [];
|
|
50
|
+
for (let i = 0; i < text.length; i += maxLen) {
|
|
51
|
+
chunks.push(text.slice(i, i + maxLen));
|
|
52
|
+
}
|
|
53
|
+
const sent = [];
|
|
54
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
55
|
+
sent.push(await conn.sendMessage(jid, { text: chunks[i], ...options }));
|
|
56
|
+
if (i < chunks.length - 1) {
|
|
57
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return sent;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Shows "typing..." presence for a bit before actually sending - makes
|
|
64
|
+
* the bot feel less robotic. `typingMs` is how long to show typing
|
|
65
|
+
* before the message goes out.
|
|
66
|
+
*/
|
|
67
|
+
async sendWithTyping(jid, content, options = {}, typingMs = 1200) {
|
|
68
|
+
try {
|
|
69
|
+
await conn.sendPresenceUpdate('composing', jid);
|
|
70
|
+
await new Promise((r) => setTimeout(r, typingMs));
|
|
71
|
+
await conn.sendPresenceUpdate('paused', jid);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
logger.debug({ err }, 'sendWithTyping: presence update failed, sending anyway');
|
|
75
|
+
}
|
|
76
|
+
return conn.sendMessage(jid, content, options);
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* sendMessage with automatic retry on transient failures (network
|
|
80
|
+
* blips, rate limiting) - NOT for permanent failures like invalid
|
|
81
|
+
* jid. Retries up to `retries` times with growing delay.
|
|
82
|
+
*/
|
|
83
|
+
async sendMessageSafe(jid, content, options = {}, retries = 3) {
|
|
84
|
+
let lastErr;
|
|
85
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
86
|
+
try {
|
|
87
|
+
return await conn.sendMessage(jid, content, options);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
lastErr = err;
|
|
91
|
+
const isLikelyTransient = /(timed out|ECONNRESET|ETIMEDOUT|rate-overlimit|Internal Server Error)/i.test(err?.message || '');
|
|
92
|
+
if (!isLikelyTransient || attempt === retries) {
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
logger.debug({ attempt, err }, 'sendMessageSafe: transient failure, retrying');
|
|
96
|
+
await new Promise((r) => setTimeout(r, 1000 * attempt));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
throw lastErr;
|
|
100
|
+
},
|
|
30
101
|
/**
|
|
31
102
|
* Downloads any URL into a Buffer - the one-liner you end up writing
|
|
32
103
|
* in every plugin that needs to grab an image/file from the internet
|
|
@@ -360,22 +431,16 @@ const makeBotToolkit = (conn, logger) => {
|
|
|
360
431
|
return false;
|
|
361
432
|
},
|
|
362
433
|
/**
|
|
363
|
-
* Asks an Anthropic model to help debug an error / snippet against
|
|
364
|
-
* THIS fork's actual Baileys source, so suggestions are grounded in
|
|
365
|
-
* what's really in your codebase instead of generic upstream advice.
|
|
366
|
-
* Wire this up to whatever command prefix you like in your own bot
|
|
367
434
|
* dispatcher (e.g. `.aimahiru`) - this function only does the actual
|
|
368
435
|
* call + prompt shaping, not command parsing.
|
|
369
436
|
*
|
|
370
437
|
* @param input.errorText the error/stack trace the user is hitting
|
|
371
438
|
* @param input.code the snippet of their bot code, if any
|
|
372
|
-
* @param input.apiKey Anthropic API key (or set ANTHROPIC_API_KEY env)
|
|
373
|
-
* @param input.model defaults to a Haiku-class model for speed/cost
|
|
374
439
|
*/
|
|
375
440
|
async aiMahiru({ errorText, code, apiKey, model = 'claude-haiku-4-5-20251001' }) {
|
|
376
|
-
const key = apiKey || process.env.
|
|
441
|
+
const key = apiKey || process.env.api_key;
|
|
377
442
|
if (!key) {
|
|
378
|
-
throw new Error('aiMahiru: no Anthropic API key provided (pass apiKey or set
|
|
443
|
+
throw new Error('aiMahiru: no Anthropic API key provided (pass apiKey or set api_key)');
|
|
379
444
|
}
|
|
380
445
|
const promptParts = [
|
|
381
446
|
'Kamu adalah Mahiru, asisten debug buat fork Baileys bernama mahiru-bails/@langitdeveloper.',
|
|
@@ -411,4 +476,4 @@ const makeBotToolkit = (conn, logger) => {
|
|
|
411
476
|
}
|
|
412
477
|
};
|
|
413
478
|
};
|
|
414
|
-
exports.makeBotToolkit = makeBotToolkit;
|
|
479
|
+
exports.makeBotToolkit = makeBotToolkit;
|
package/lib/Utils/generics.js
CHANGED
|
@@ -503,4 +503,4 @@ exports.bytesToCrockford = bytesToCrockford;
|
|
|
503
503
|
const encodeNewsletterMessage = (message) => {
|
|
504
504
|
return WAProto_1.proto.Message.encode(message).finish()
|
|
505
505
|
}
|
|
506
|
-
exports.encodeNewsletterMessage = encodeNewsletterMessage;
|
|
506
|
+
exports.encodeNewsletterMessage = encodeNewsletterMessage;
|
package/lib/Utils/messages.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.getAggregateVotesInPollMessage = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText =
|
|
6
|
+
exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.getAggregateVotesInPollMessage = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
|
|
7
7
|
const boom_1 = require("@hapi/boom");
|
|
8
8
|
const axios_1 = __importDefault(require("axios"));
|
|
9
9
|
const crypto_1 = require("crypto");
|
|
@@ -219,39 +219,6 @@ const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
|
219
219
|
return Types_1.WAProto.Message.fromObject(content);
|
|
220
220
|
};
|
|
221
221
|
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
|
|
222
|
-
/**
|
|
223
|
-
* Wrapper helper to build a `richMessage` content object.
|
|
224
|
-
* Accepts either the flat shape directly:
|
|
225
|
-
* prepareRichResponseMessage({ text: '...', code: { language: 'js', code: '...' } })
|
|
226
|
-
* or a `richResponse` array of fragments (merged automatically: text fragments
|
|
227
|
-
* are joined with a blank line, other keys keep the first value seen):
|
|
228
|
-
* prepareRichResponseMessage({ richResponse: [{ text: '...' }, { code: {...} }] })
|
|
229
|
-
*/
|
|
230
|
-
const prepareRichResponseMessage = (input) => {
|
|
231
|
-
if (input && Array.isArray(input.richResponse)) {
|
|
232
|
-
const merged = {};
|
|
233
|
-
const texts = [];
|
|
234
|
-
for (const item of input.richResponse) {
|
|
235
|
-
if (!item || typeof item !== 'object') {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
for (const k of Object.keys(item)) {
|
|
239
|
-
if (k === 'text') {
|
|
240
|
-
texts.push(item.text);
|
|
241
|
-
}
|
|
242
|
-
else if (merged[k] === undefined) {
|
|
243
|
-
merged[k] = item[k];
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
if (texts.length) {
|
|
248
|
-
merged.text = texts.join('\n\n');
|
|
249
|
-
}
|
|
250
|
-
return { richMessage: merged };
|
|
251
|
-
}
|
|
252
|
-
return { richMessage: input };
|
|
253
|
-
};
|
|
254
|
-
exports.prepareRichResponseMessage = prepareRichResponseMessage;
|
|
255
222
|
/**
|
|
256
223
|
* Generate forwarded message content like WA does
|
|
257
224
|
* @param message the message to forward
|
|
@@ -413,338 +380,6 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
413
380
|
else if ('requestPhoneNumber' in message) {
|
|
414
381
|
m.requestPhoneNumberMessage = {};
|
|
415
382
|
}
|
|
416
|
-
else if ('richMessage' in message) {
|
|
417
|
-
const { randomUUID } = require('crypto');
|
|
418
|
-
const rich = message.richMessage;
|
|
419
|
-
const submessages = [];
|
|
420
|
-
const sections = [];
|
|
421
|
-
const richResponseSources = [];
|
|
422
|
-
|
|
423
|
-
const extractIE = (text) => {
|
|
424
|
-
let ie = [], result = '', last = 0, citation_index = 1, hyperlink_index = 0, latex_index = 0, stack = [];
|
|
425
|
-
for (let i = 0; i < text.length; i++) {
|
|
426
|
-
if (text[i] == '[' && text[i - 1] != '\\') {
|
|
427
|
-
stack.push(i);
|
|
428
|
-
} else if (text[i] == ']' && (text[i + 1] == '(' || text[i + 1] == '<')) {
|
|
429
|
-
let start = stack.pop();
|
|
430
|
-
if (start == null) continue;
|
|
431
|
-
let open = text[i + 1], close = open == '(' ? ')' : '>', type = open == '(' ? 'link' : 'latex', end = i + 2, depth = 1;
|
|
432
|
-
while (end < text.length && depth) {
|
|
433
|
-
if (text[end] == open && text[end - 1] != '\\') depth++;
|
|
434
|
-
else if (text[end] == close && text[end - 1] != '\\') depth--;
|
|
435
|
-
end++;
|
|
436
|
-
}
|
|
437
|
-
if (depth) continue;
|
|
438
|
-
let raw = text.slice(start + 1, i).trim(), url = text.slice(i + 2, end - 1).trim(), key, tag, data;
|
|
439
|
-
if (type == 'latex') {
|
|
440
|
-
let [txt = '', width = null, height = null, font_height = null, padding = null] = raw.split('|');
|
|
441
|
-
key = `LATEX_${latex_index++}`;
|
|
442
|
-
tag = `{{${key}}}${txt || 'image'}{{/${key}}}`;
|
|
443
|
-
data = { type: 'latex', ie: { key, text: txt, url, width, height, font_height, padding } };
|
|
444
|
-
} else if (raw) {
|
|
445
|
-
key = `HLINK_${hyperlink_index++}`;
|
|
446
|
-
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
447
|
-
data = { type: 'hyperlink', ie: { key, text: raw, url } };
|
|
448
|
-
} else {
|
|
449
|
-
key = `CITE_${citation_index - 1}`;
|
|
450
|
-
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
451
|
-
data = { type: 'citation', ie: { reference_id: citation_index++, key, text: '', url } };
|
|
452
|
-
}
|
|
453
|
-
result += text.slice(last, start) + tag;
|
|
454
|
-
last = end;
|
|
455
|
-
ie.push(data);
|
|
456
|
-
i = end - 1;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
result += text.slice(last);
|
|
460
|
-
return { text: result, ie };
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
const tokenizer = (code, lang = 'javascript') => {
|
|
464
|
-
const keywordsMap = {
|
|
465
|
-
javascript: new Set(['break','case','catch','continue','debugger','delete','do','else','finally','for','function','if','in','instanceof','new','return','switch','this','throw','try','typeof','var','void','while','with','true','false','null','undefined','class','const','let','super','extends','export','import','yield','static','constructor','async','await','get','set'])
|
|
466
|
-
};
|
|
467
|
-
const TYPE_MAP = { 0:'DEFAULT', 1:'KEYWORD', 2:'METHOD', 3:'STR', 4:'NUMBER', 5:'COMMENT' };
|
|
468
|
-
const keywords = keywordsMap[lang] || new Set();
|
|
469
|
-
const tokens = [];
|
|
470
|
-
let i = 0;
|
|
471
|
-
const push = (content, type) => {
|
|
472
|
-
if (!content) return;
|
|
473
|
-
const last = tokens[tokens.length - 1];
|
|
474
|
-
if (last && last.highlightType === type) last.codeContent += content;
|
|
475
|
-
else tokens.push({ codeContent: content, highlightType: type });
|
|
476
|
-
};
|
|
477
|
-
while (i < code.length) {
|
|
478
|
-
const c = code[i];
|
|
479
|
-
if (/\s/.test(c)) { let s = i; while (i < code.length && /\s/.test(code[i])) i++; push(code.slice(s, i), 0); continue; }
|
|
480
|
-
if (c === '/' && code[i + 1] === '/') { let s = i; i += 2; while (i < code.length && code[i] !== '\n') i++; push(code.slice(s, i), 5); continue; }
|
|
481
|
-
if (c === '"' || c === "'" || c === '`') { let s = i; const q = c; i++; while (i < code.length) { if (code[i] === '\\' && i + 1 < code.length) i += 2; else if (code[i] === q) { i++; break; } else i++; } push(code.slice(s, i), 3); continue; }
|
|
482
|
-
if (/[0-9]/.test(c)) { let s = i; while (i < code.length && /[0-9.]/.test(code[i])) i++; push(code.slice(s, i), 4); continue; }
|
|
483
|
-
if (/[a-zA-Z_$]/.test(c)) { let s = i; while (i < code.length && /[a-zA-Z0-9_$]/.test(code[i])) i++; const word = code.slice(s, i); let type = 0; if (keywords.has(word)) type = 1; else { let j = i; while (j < code.length && /\s/.test(code[j])) j++; if (code[j] === '(') type = 2; } push(word, type); continue; }
|
|
484
|
-
push(c, 0); i++;
|
|
485
|
-
}
|
|
486
|
-
return { codeBlock: tokens, unified_codeBlock: tokens.map(t => ({ content: t.codeContent, type: TYPE_MAP[t.highlightType] })) };
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
const toTableMetadata = (arr) => {
|
|
490
|
-
const [header, ...rows] = arr;
|
|
491
|
-
const maxLen = Math.max(header.length, ...rows.map(r => r.length));
|
|
492
|
-
const normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')];
|
|
493
|
-
const unified_rows = [{ is_header: true, cells: normalize(header) }, ...rows.map(r => ({ is_header: false, cells: normalize(r) }))];
|
|
494
|
-
const rowsMeta = unified_rows.map(r => ({ items: r.cells, ...(r.is_header ? { isHeading: true } : {}) }));
|
|
495
|
-
return { title: '', rows: rowsMeta, unified_rows };
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
if (rich.text) {
|
|
499
|
-
const parsed = typeof rich.text === 'string' ? extractIE(rich.text) : rich.text;
|
|
500
|
-
const text = parsed.text || parsed;
|
|
501
|
-
const inline_entities = parsed.ie ? parsed.ie.map(({ type, ie }) => {
|
|
502
|
-
if (type === 'hyperlink') return { key: ie.key, metadata: { display_name: ie.text, is_trusted: true, url: ie.url, __typename: 'GenAIInlineLinkItem' } };
|
|
503
|
-
if (type === 'citation') return { key: ie.key, metadata: { reference_id: ie.reference_id, reference_url: ie.url, reference_title: ie.url, reference_display_name: ie.url, sources: [], __typename: 'GenAISearchCitationItem' } };
|
|
504
|
-
if (type === 'latex') return { key: ie.key, metadata: { latex_expression: ie.text || '', latex_image: { url: ie.url, width: Number(ie.width) || 100, height: Number(ie.height) || 100 }, font_height: Number(ie.font_height) || 83.33, padding: Number(ie.padding) || 15, __typename: 'GenAILatexItem' } };
|
|
505
|
-
return null;
|
|
506
|
-
}).filter(Boolean) : [];
|
|
507
|
-
submessages.push({ messageType: 2, messageText: text });
|
|
508
|
-
sections.push({
|
|
509
|
-
view_model: {
|
|
510
|
-
primitive: { text, inline_entities, __typename: 'GenAIMarkdownTextUXPrimitive' },
|
|
511
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
if (rich.code) {
|
|
517
|
-
const { language, code } = rich.code;
|
|
518
|
-
const tok = tokenizer(code, language);
|
|
519
|
-
submessages.push({ messageType: 5, codeMetadata: { codeLanguage: language, codeBlocks: tok.codeBlock } });
|
|
520
|
-
sections.push({
|
|
521
|
-
view_model: {
|
|
522
|
-
primitive: { language, code_blocks: tok.unified_codeBlock, __typename: 'GenAICodeUXPrimitive' },
|
|
523
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if (rich.table) {
|
|
529
|
-
const meta = toTableMetadata(rich.table);
|
|
530
|
-
submessages.push({ messageType: 4, tableMetadata: { title: meta.title, rows: meta.rows } });
|
|
531
|
-
sections.push({
|
|
532
|
-
view_model: {
|
|
533
|
-
primitive: { rows: meta.unified_rows, __typename: 'GenATableUXPrimitive' },
|
|
534
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (rich.images) {
|
|
540
|
-
const urls = Array.isArray(rich.images) ? rich.images : [rich.images];
|
|
541
|
-
submessages.push({
|
|
542
|
-
messageType: 1,
|
|
543
|
-
gridImageMetadata: {
|
|
544
|
-
gridImageUrl: { imagePreviewUrl: urls[0] },
|
|
545
|
-
imageUrls: urls.map(url => ({ imagePreviewUrl: url, imageHighResUrl: url, sourceUrl: 'https://www.levvicode.cloud/' }))
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
urls.forEach(url => {
|
|
549
|
-
sections.push({
|
|
550
|
-
view_model: {
|
|
551
|
-
primitive: { media: { url, mime_type: 'image/jpeg' }, imagine_type: 3, status: { status: 'READY' }, __typename: 'GenAIImaginePrimitive' },
|
|
552
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (rich.video) {
|
|
559
|
-
submessages.push({ messageType: 2, messageText: '[ CANNOT_LOAD_VIDEO ]' });
|
|
560
|
-
sections.push({
|
|
561
|
-
view_model: {
|
|
562
|
-
primitive: {
|
|
563
|
-
media: { url: rich.video, mime_type: 'video/mp4', duration: 10 },
|
|
564
|
-
imagine_type: 'ANIMATE',
|
|
565
|
-
status: { status: 'READY' },
|
|
566
|
-
__typename: 'GenAIImaginePrimitive'
|
|
567
|
-
},
|
|
568
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
if (rich.productSingle) {
|
|
574
|
-
submessages.push({ messageType: 2, messageText: '[ CANNOT_LOAD_PRODUCT ]' });
|
|
575
|
-
sections.push({
|
|
576
|
-
view_model: {
|
|
577
|
-
primitive: { ...rich.productSingle, __typename: 'GenAIProductItemCardPrimitive' },
|
|
578
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (rich.productMultiple) {
|
|
584
|
-
submessages.push({ messageType: 2, messageText: '[ CANNOT_LOAD_PRODUCT ]' });
|
|
585
|
-
sections.push({
|
|
586
|
-
view_model: {
|
|
587
|
-
primitives: rich.productMultiple.map(p => ({ ...p, __typename: 'GenAIProductItemCardPrimitive' })),
|
|
588
|
-
__typename: 'GenAIHScrollLayoutViewModel'
|
|
589
|
-
}
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
if (rich.product && !rich.productSingle && !rich.productMultiple) {
|
|
594
|
-
submessages.push({ messageType: 2, messageText: '[ CANNOT_LOAD_PRODUCT ]' });
|
|
595
|
-
if (Array.isArray(rich.product)) {
|
|
596
|
-
sections.push({
|
|
597
|
-
view_model: {
|
|
598
|
-
primitives: rich.product.map(p => ({ ...p, __typename: 'GenAIProductItemCardPrimitive' })),
|
|
599
|
-
__typename: 'GenAIHScrollLayoutViewModel'
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
} else {
|
|
603
|
-
sections.push({
|
|
604
|
-
view_model: {
|
|
605
|
-
primitive: { ...rich.product, __typename: 'GenAIProductItemCardPrimitive' },
|
|
606
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
if (rich.post) {
|
|
613
|
-
submessages.push({ messageType: 2, messageText: '[ CANNOT_LOAD_POST ]' });
|
|
614
|
-
if (Array.isArray(rich.post)) {
|
|
615
|
-
sections.push({
|
|
616
|
-
view_model: {
|
|
617
|
-
primitives: rich.post.map(p => ({ ...p, __typename: 'GenAIPostPrimitive' })),
|
|
618
|
-
__typename: 'GenAIHScrollLayoutViewModel'
|
|
619
|
-
}
|
|
620
|
-
});
|
|
621
|
-
} else {
|
|
622
|
-
sections.push({
|
|
623
|
-
view_model: {
|
|
624
|
-
primitive: { ...rich.post, __typename: 'GenAIPostPrimitive' },
|
|
625
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (rich.reels) {
|
|
632
|
-
const items = Array.isArray(rich.reels) ? rich.reels : [rich.reels];
|
|
633
|
-
submessages.push({
|
|
634
|
-
messageType: 9,
|
|
635
|
-
contentItemsMetadata: {
|
|
636
|
-
contentType: 1,
|
|
637
|
-
itemsMetadata: items.map(i => ({
|
|
638
|
-
reelItem: { title: i.title, profileIconUrl: i.profileIconUrl, thumbnailUrl: i.thumbnailUrl, videoUrl: i.videoUrl }
|
|
639
|
-
}))
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
sections.push({
|
|
643
|
-
view_model: {
|
|
644
|
-
primitives: items.map(i => ({
|
|
645
|
-
reels_url: i.videoUrl,
|
|
646
|
-
thumbnail_url: i.thumbnailUrl,
|
|
647
|
-
creator: i.title,
|
|
648
|
-
avatar_url: i.profileIconUrl,
|
|
649
|
-
reels_title: i.reels_title || '',
|
|
650
|
-
likes_count: i.likes_count || 0,
|
|
651
|
-
shares_count: i.shares_count || 0,
|
|
652
|
-
view_count: i.view_count || 0,
|
|
653
|
-
reel_source: i.reel_source || 'IG',
|
|
654
|
-
is_verified: i.is_verified || false,
|
|
655
|
-
__typename: 'GenAIReelPrimitive'
|
|
656
|
-
})),
|
|
657
|
-
__typename: 'GenAIHScrollLayoutViewModel'
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
items.forEach((i, idx) => richResponseSources.push({
|
|
661
|
-
provider: 'MahiruBaileys',
|
|
662
|
-
thumbnailCDNURL: i.thumbnailUrl,
|
|
663
|
-
sourceProviderURL: i.videoUrl,
|
|
664
|
-
sourceQuery: '',
|
|
665
|
-
faviconCDNURL: i.profileIconUrl,
|
|
666
|
-
citationNumber: idx + 1,
|
|
667
|
-
sourceTitle: i.title
|
|
668
|
-
}));
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
if (rich.sources) {
|
|
672
|
-
const sourceArr = Array.isArray(rich.sources) ? rich.sources : [rich.sources];
|
|
673
|
-
sections.push({
|
|
674
|
-
view_model: {
|
|
675
|
-
primitive: {
|
|
676
|
-
sources: sourceArr.map(s => typeof s === 'object' ? s : {
|
|
677
|
-
source_type: 'THIRD_PARTY',
|
|
678
|
-
source_display_name: s[2] || '',
|
|
679
|
-
source_subtitle: 'AI',
|
|
680
|
-
source_url: s[1] || '',
|
|
681
|
-
favicon: { url: s[0] || '', mime_type: 'image/jpeg', width: 16, height: 16 }
|
|
682
|
-
}),
|
|
683
|
-
__typename: 'GenAISearchResultPrimitive'
|
|
684
|
-
},
|
|
685
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
if (rich.tip) {
|
|
691
|
-
submessages.push({ messageType: 2, messageText: rich.tip });
|
|
692
|
-
sections.push({
|
|
693
|
-
view_model: {
|
|
694
|
-
primitive: { text: rich.tip, __typename: 'GenAIMetadataTextPrimitive' },
|
|
695
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
696
|
-
}
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
if (rich.suggestions) {
|
|
701
|
-
sections.push({
|
|
702
|
-
view_model: {
|
|
703
|
-
primitives: rich.suggestions.map(s => ({
|
|
704
|
-
prompt_text: s,
|
|
705
|
-
prompt_type: 'SUGGESTED_PROMPT',
|
|
706
|
-
__typename: 'GenAIFollowUpSuggestionPillPrimitive'
|
|
707
|
-
})),
|
|
708
|
-
__typename: 'GenAIActionRowLayoutViewModel'
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
if (rich.footer) {
|
|
714
|
-
sections.push({
|
|
715
|
-
view_model: {
|
|
716
|
-
primitive: { text: rich.footer, __typename: 'GenAIMetadataTextPrimitive' },
|
|
717
|
-
__typename: 'GenAISingleLayoutViewModel'
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
const unifiedData = { response_id: randomUUID(), sections };
|
|
723
|
-
|
|
724
|
-
m = {
|
|
725
|
-
messageContextInfo: {
|
|
726
|
-
deviceListMetadata: {},
|
|
727
|
-
deviceListMetadataVersion: 2,
|
|
728
|
-
botMetadata: {
|
|
729
|
-
messageDisclaimerText: rich.title || '',
|
|
730
|
-
richResponseSourcesMetadata: { sources: richResponseSources }
|
|
731
|
-
}
|
|
732
|
-
},
|
|
733
|
-
richResponseMessage: {
|
|
734
|
-
messageType: 1,
|
|
735
|
-
submessages,
|
|
736
|
-
unifiedResponse: {
|
|
737
|
-
data: Buffer.from(JSON.stringify(unifiedData)).toString('base64')
|
|
738
|
-
},
|
|
739
|
-
contextInfo: {
|
|
740
|
-
forwardingScore: 1,
|
|
741
|
-
isForwarded: true,
|
|
742
|
-
forwardedAiBotMessageInfo: { botJid: '0@bot' },
|
|
743
|
-
forwardOrigin: 4
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
383
|
else {
|
|
749
384
|
m = await (0, exports.prepareWAMessageMedia)(message, options);
|
|
750
385
|
}
|
|
@@ -29,7 +29,12 @@ const useMultiFileAuthState = async (folder) => {
|
|
|
29
29
|
const mutex = getFileLock(filePath);
|
|
30
30
|
return mutex.acquire().then(async (release) => {
|
|
31
31
|
try {
|
|
32
|
-
|
|
32
|
+
// write to a temp file first, then rename - rename is atomic on
|
|
33
|
+
// the same filesystem, so a crash/kill mid-write can never leave
|
|
34
|
+
// creds.json (or any key file) half-written/corrupted
|
|
35
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
36
|
+
await (0, promises_1.writeFile)(tmpPath, JSON.stringify(data, generics_1.BufferJSON.replacer));
|
|
37
|
+
await (0, promises_1.rename)(tmpPath, filePath);
|
|
33
38
|
}
|
|
34
39
|
finally {
|
|
35
40
|
release();
|