@vanzxy/baileys 1.5.2 → 1.5.4
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/chats.js +27 -4
- package/lib/Utils/MessageBuilder.js +179 -122
- package/lib/Utils/MessageBuilder_d.ts +5 -0
- package/package.json +1 -1
package/lib/Socket/chats.js
CHANGED
|
@@ -706,12 +706,35 @@ export const makeChatsSocket = (config) => {
|
|
|
706
706
|
ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
|
|
707
707
|
}
|
|
708
708
|
};
|
|
709
|
+
// Vanz@Fix 24-08-26 --- appPatch() (used by updateProfileName/archive/mute/pin/etc — anything
|
|
710
|
+
// going through the app-state WRITE path) threw "App state key not present!" immediately if
|
|
711
|
+
// myAppStateKeyId wasn't set yet, with zero retry. The READ path (resyncAppState, above) already
|
|
712
|
+
// has a courtesy retry via blockedCollections + the creds.update listener below — the key
|
|
713
|
+
// arrives async after connect (APP_STATE_SYNC_KEY_SHARE), so calling e.g. updateProfileName()
|
|
714
|
+
// right after connection.update === 'open' would reliably fail on a fresh/early connection.
|
|
715
|
+
// Now appPatch() waits (bounded, 10s default) for the same creds.update event before giving up,
|
|
716
|
+
// instead of failing hard on what's usually just a timing race.
|
|
717
|
+
const waitForAppStateKeyId = (timeoutMs = 10_000) => {
|
|
718
|
+
if (authState.creds.myAppStateKeyId) {
|
|
719
|
+
return Promise.resolve(authState.creds.myAppStateKeyId);
|
|
720
|
+
}
|
|
721
|
+
return new Promise((resolve, reject) => {
|
|
722
|
+
const timeout = setTimeout(() => {
|
|
723
|
+
ev.off('creds.update', onUpdate);
|
|
724
|
+
reject(new Boom('App state key not present!', { statusCode: 400 }));
|
|
725
|
+
}, timeoutMs);
|
|
726
|
+
const onUpdate = ({ myAppStateKeyId }) => {
|
|
727
|
+
if (!myAppStateKeyId) return;
|
|
728
|
+
clearTimeout(timeout);
|
|
729
|
+
ev.off('creds.update', onUpdate);
|
|
730
|
+
resolve(myAppStateKeyId);
|
|
731
|
+
};
|
|
732
|
+
ev.on('creds.update', onUpdate);
|
|
733
|
+
});
|
|
734
|
+
};
|
|
709
735
|
const appPatch = async (patchCreate) => {
|
|
710
736
|
const name = patchCreate.type;
|
|
711
|
-
const myAppStateKeyId =
|
|
712
|
-
if (!myAppStateKeyId) {
|
|
713
|
-
throw new Boom('App state key not present!', { statusCode: 400 });
|
|
714
|
-
}
|
|
737
|
+
const myAppStateKeyId = await waitForAppStateKeyId();
|
|
715
738
|
let initial;
|
|
716
739
|
let encodeResult;
|
|
717
740
|
await appStatePatchMutex.mutex(async () => {
|
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
const MESSAGE_BUILDER_VERSION = '4.9';
|
|
48
48
|
|
|
49
49
|
import { generateWAMessageFromContent, prepareWAMessageMedia } from './messages.js';
|
|
50
|
+
import { generateMessageIDV2 } from './generics.js';
|
|
51
|
+
import { botMetadataSignature, botMetadataCertificate } from './rich-message-utils.js';
|
|
50
52
|
import crypto from 'crypto';
|
|
51
53
|
import { PassThrough, Readable } from 'stream';
|
|
52
54
|
// Vanz@Fix 15-08-26 --- sharp/fluent-ffmpeg were statically imported in the blurose source.
|
|
@@ -292,15 +294,19 @@ class Toolkit {
|
|
|
292
294
|
return await waitAllPromises(input);
|
|
293
295
|
}
|
|
294
296
|
|
|
295
|
-
/** Fetch `url` into a Buffer. @param {boolean} [silent] Return an empty Buffer instead of throwing on failure. */
|
|
296
|
-
static async fetchBuffer(url, options = {}, { silent = true } = {}) {
|
|
297
|
+
/** Fetch `url` into a Buffer. @param {boolean} [silent] Return an empty Buffer instead of throwing on failure. @param {number} [timeout] Abort after this many ms (default 15s) instead of hanging indefinitely on a dead/slow host. */
|
|
298
|
+
static async fetchBuffer(url, options = {}, { silent = true, timeout = 15000 } = {}) {
|
|
299
|
+
const controller = new AbortController();
|
|
300
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
297
301
|
try {
|
|
298
|
-
let response = await fetch(url, options);
|
|
302
|
+
let response = await fetch(url, { ...options, signal: options.signal ?? controller.signal });
|
|
299
303
|
if (!response.ok) throw Error(`HTTP ${response.status}`);
|
|
300
304
|
return Buffer.from(await response.arrayBuffer());
|
|
301
305
|
} catch (error) {
|
|
302
306
|
if (silent) return Buffer.alloc(0);
|
|
303
307
|
throw error;
|
|
308
|
+
} finally {
|
|
309
|
+
clearTimeout(timer);
|
|
304
310
|
}
|
|
305
311
|
}
|
|
306
312
|
|
|
@@ -1180,14 +1186,6 @@ class Button extends BaseBuilder {
|
|
|
1180
1186
|
}
|
|
1181
1187
|
|
|
1182
1188
|
/** Build and send this interactive message. @param {string} jid Destination chat/group jid. */
|
|
1183
|
-
async sendEdit(jid, messageId, { ...options } = {}) {
|
|
1184
|
-
if (!messageId) throw new Error('messageId is required');
|
|
1185
|
-
const msg = await this.build(jid, options);
|
|
1186
|
-
msg.key = { ...(msg.key || {}), remoteJid: jid, id: messageId, fromMe: true };
|
|
1187
|
-
await this.#client.relayMessage(jid, msg.message, { messageId, ...options });
|
|
1188
|
-
return msg;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
1189
|
async send(jid, { ...options } = {}) {
|
|
1192
1190
|
const msg = await this.build(jid, options);
|
|
1193
1191
|
|
|
@@ -1594,9 +1592,21 @@ class AIRich extends BaseBuilder {
|
|
|
1594
1592
|
// mediaKey still doesn't render, so it's a trust-chain gate, not a domain/encoding issue).
|
|
1595
1593
|
// Track every addInlineImage() call here so send() can fall back to a normal imageMessage.
|
|
1596
1594
|
this._inlineImages = [];
|
|
1597
|
-
|
|
1598
|
-
//
|
|
1599
|
-
this.
|
|
1595
|
+
|
|
1596
|
+
// Vanz@Add 24-08-26 --- ported from temen's MessageBuilderV4.7 (setResponseId/setBotResponseId
|
|
1597
|
+
// below), rewritten to fit this fork's conventions. build() used to always mint a fresh
|
|
1598
|
+
// crypto.randomUUID() for both unifiedResponse.response_id and botMetadata.botResponseId on
|
|
1599
|
+
// every call, with no way to reuse one — so a `sendEdit()`-style flow (rebuild the same
|
|
1600
|
+
// message with updated content, same response_id, so WA patches it in place instead of
|
|
1601
|
+
// showing a new message) was never actually possible despite being in the gist example.
|
|
1602
|
+
// null here means "not pinned yet" — build() falls back to a fresh randomUUID() same as before
|
|
1603
|
+
// when neither setResponseId() nor setBotResponseId() has been called.
|
|
1604
|
+
this._responseId = null;
|
|
1605
|
+
this._botResponseId = null;
|
|
1606
|
+
|
|
1607
|
+
// Vanz@Add --- set by send()/sendEdit() after every relay so a follow-up sendEdit(), called
|
|
1608
|
+
// with no args, knows which jid/message id to patch in place (matches temen's v4.7 API).
|
|
1609
|
+
this._lastMessageKey = null;
|
|
1600
1610
|
|
|
1601
1611
|
// Vanz@Add (v4.9.1) --- { id, insertAt } support for every add*()/set*() call, without
|
|
1602
1612
|
// touching each method's own body/signature. Every add*() call ends up pushing 0-N items
|
|
@@ -1915,7 +1925,7 @@ class AIRich extends BaseBuilder {
|
|
|
1915
1925
|
* One image, no prompt, nothing to download — use this when you don't need the rich card,
|
|
1916
1926
|
* just the picture to show up immediately.
|
|
1917
1927
|
*/
|
|
1918
|
-
addImage(imageUrl, { resolveUrl = false, instant =
|
|
1928
|
+
addImage(imageUrl, { resolveUrl = false, instant = false } = {}) {
|
|
1919
1929
|
if (!(typeof imageUrl === 'string' || Buffer.isBuffer(imageUrl) || (Array.isArray(imageUrl) && imageUrl.every((v) => typeof v === 'string' || Buffer.isBuffer(v))))) {
|
|
1920
1930
|
throw new TypeError('imageUrl must be string | buffer | array of string/buffer');
|
|
1921
1931
|
}
|
|
@@ -1973,8 +1983,6 @@ class AIRich extends BaseBuilder {
|
|
|
1973
1983
|
}
|
|
1974
1984
|
|
|
1975
1985
|
if (instant) {
|
|
1976
|
-
this._mediaFallbacks.push({ type: 'image', url: imagePreviewUrl, caption: undefined });
|
|
1977
|
-
// Keep legacy inline queue in sync for callers that inspect it.
|
|
1978
1986
|
this._inlineImages.push({ url: imagePreviewUrl, caption: undefined });
|
|
1979
1987
|
}
|
|
1980
1988
|
});
|
|
@@ -2052,7 +2060,7 @@ class AIRich extends BaseBuilder {
|
|
|
2052
2060
|
// for before rendering. Mirrors addImage()'s { resolveUrl } — when true, the url is uploaded to
|
|
2053
2061
|
// WA's own media server first via Toolkit.toUrl() so it renders instantly like WA-native media.
|
|
2054
2062
|
/** Add a video block. */
|
|
2055
|
-
addVideo(videoUrl, { autoFill = false, resolveUrl = false
|
|
2063
|
+
addVideo(videoUrl, { autoFill = false, resolveUrl = false } = {}) {
|
|
2056
2064
|
const isObjectVideo = (v) => v && typeof v === 'object' && v.url;
|
|
2057
2065
|
|
|
2058
2066
|
const isValidPrimitive =
|
|
@@ -2129,15 +2137,6 @@ class AIRich extends BaseBuilder {
|
|
|
2129
2137
|
__typename: 'GenAIImaginePrimitive',
|
|
2130
2138
|
})
|
|
2131
2139
|
);
|
|
2132
|
-
|
|
2133
|
-
if (instant) {
|
|
2134
|
-
this._mediaFallbacks.push({
|
|
2135
|
-
type: 'video',
|
|
2136
|
-
url,
|
|
2137
|
-
caption: isObject ? (item.caption ?? '') : '',
|
|
2138
|
-
mimetype: isObject ? (item.mime_type ?? 'video/mp4') : 'video/mp4',
|
|
2139
|
-
});
|
|
2140
|
-
}
|
|
2141
2140
|
});
|
|
2142
2141
|
|
|
2143
2142
|
return this;
|
|
@@ -2224,6 +2223,56 @@ class AIRich extends BaseBuilder {
|
|
|
2224
2223
|
return this;
|
|
2225
2224
|
}
|
|
2226
2225
|
|
|
2226
|
+
// Vanz@Add 24-08-26 --- ported from temen's MessageBuilderV4.7 (setResponseId/setBotResponseId/
|
|
2227
|
+
// refreshResponseId/refreshBotResponseId), rewritten for this fork. Pins the two ids build()
|
|
2228
|
+
// generates (see constructor comment) so a rebuilt message can reuse the same response_id/
|
|
2229
|
+
// botResponseId — needed for editing an already-sent AIRich message in place.
|
|
2230
|
+
|
|
2231
|
+
/** Pin `unifiedResponse.response_id` to a specific value instead of a fresh random one each build() — needed to re-send an edited version of an already-sent message in place. */
|
|
2232
|
+
setResponseId(id) {
|
|
2233
|
+
if (typeof id !== 'string' || !id) throw new TypeError('setResponseId(id) requires a non-empty string');
|
|
2234
|
+
this._responseId = id;
|
|
2235
|
+
return this;
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/** Un-pin `unifiedResponse.response_id`, generating a fresh crypto.randomUUID() immediately (not deferred to the next build()). */
|
|
2239
|
+
refreshResponseId() {
|
|
2240
|
+
this._responseId = crypto.randomUUID();
|
|
2241
|
+
return this;
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
/** Pin `botMetadata.botResponseId` to a specific value instead of a fresh random one each build(). */
|
|
2245
|
+
setBotResponseId(id) {
|
|
2246
|
+
if (typeof id !== 'string' || !id) throw new TypeError('setBotResponseId(id) requires a non-empty string');
|
|
2247
|
+
this._botResponseId = id;
|
|
2248
|
+
return this;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
/** Un-pin `botMetadata.botResponseId`, generating a fresh crypto.randomUUID() immediately. */
|
|
2252
|
+
refreshBotResponseId() {
|
|
2253
|
+
this._botResponseId = crypto.randomUUID();
|
|
2254
|
+
return this;
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
/** Add a small metadata-style text line (`GenAIMetadataTextPrimitive`) — same visual style as the auto-appended footer/`addTip()`'s callout, but insertable anywhere and without `addTip()`'s icon prefix. */
|
|
2258
|
+
addMetadata(text) {
|
|
2259
|
+
if (typeof text !== 'string' || !text) throw new TypeError('addMetadata(text) requires a non-empty string');
|
|
2260
|
+
|
|
2261
|
+
this._submessages.push({
|
|
2262
|
+
messageType: 2,
|
|
2263
|
+
messageText: text,
|
|
2264
|
+
});
|
|
2265
|
+
|
|
2266
|
+
this._sections.push(
|
|
2267
|
+
AIRich.newLayout('Single', {
|
|
2268
|
+
text,
|
|
2269
|
+
__typename: 'GenAIMetadataTextPrimitive',
|
|
2270
|
+
})
|
|
2271
|
+
);
|
|
2272
|
+
|
|
2273
|
+
return this;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2227
2276
|
/** Add a small "tip" callout banner. @param {string} text */
|
|
2228
2277
|
addTip(text) {
|
|
2229
2278
|
if (typeof text !== 'string' || !text) {
|
|
@@ -2301,7 +2350,6 @@ class AIRich extends BaseBuilder {
|
|
|
2301
2350
|
__typename: 'GenAIImagePrimitive',
|
|
2302
2351
|
})
|
|
2303
2352
|
);
|
|
2304
|
-
this._mediaFallbacks.push({ type: 'image', url: full || preview, caption: undefined });
|
|
2305
2353
|
|
|
2306
2354
|
return this;
|
|
2307
2355
|
}
|
|
@@ -2641,6 +2689,18 @@ class AIRich extends BaseBuilder {
|
|
|
2641
2689
|
]
|
|
2642
2690
|
: [...(await waitAllPromises(this._sections))];
|
|
2643
2691
|
|
|
2692
|
+
// Vanz@Merge 15-08-26 --- Neither blurose nor arslan sign the bot metadata with
|
|
2693
|
+
// verificationMetadata (proofs/certificateChain). Backported from this project's own
|
|
2694
|
+
// rich-message-utils.js botMetadataSignature/botMetadataCertificate helpers, plus a
|
|
2695
|
+
// botResponseId tying the signed metadata to unifiedResponse.response_id.
|
|
2696
|
+
// Vanz@Fix 24-08-26 --- was `const responseId = crypto.randomUUID()` shared for BOTH
|
|
2697
|
+
// unifiedResponse.response_id and botMetadata.botResponseId, generated fresh every build()
|
|
2698
|
+
// with no override. Now each has its own id, pinned via setResponseId()/setBotResponseId()
|
|
2699
|
+
// if the caller set one (for sendEdit()-style in-place message updates), otherwise still
|
|
2700
|
+
// defaults to a fresh randomUUID() per build() exactly like before.
|
|
2701
|
+
const responseId = this._responseId ?? crypto.randomUUID();
|
|
2702
|
+
const botResponseId = this._botResponseId ?? crypto.randomUUID();
|
|
2703
|
+
|
|
2644
2704
|
return {
|
|
2645
2705
|
messageContextInfo: {
|
|
2646
2706
|
deviceListMetadata: {},
|
|
@@ -2648,6 +2708,17 @@ class AIRich extends BaseBuilder {
|
|
|
2648
2708
|
botMetadata: {
|
|
2649
2709
|
messageDisclaimerText: this._title,
|
|
2650
2710
|
richResponseSourcesMetadata: { sources: this._richResponseSources },
|
|
2711
|
+
botResponseId: botResponseId,
|
|
2712
|
+
verificationMetadata: {
|
|
2713
|
+
proofs: [
|
|
2714
|
+
{
|
|
2715
|
+
certificateChain: [botMetadataCertificate(), botMetadataCertificate(892)],
|
|
2716
|
+
version: 1,
|
|
2717
|
+
useCase: 1,
|
|
2718
|
+
signature: botMetadataSignature(),
|
|
2719
|
+
},
|
|
2720
|
+
],
|
|
2721
|
+
},
|
|
2651
2722
|
...notif,
|
|
2652
2723
|
},
|
|
2653
2724
|
},
|
|
@@ -2658,7 +2729,7 @@ class AIRich extends BaseBuilder {
|
|
|
2658
2729
|
messageType: 1,
|
|
2659
2730
|
submessages: includesSubmessages ? await waitAllPromises(this._submessages) : [],
|
|
2660
2731
|
unifiedResponse: {
|
|
2661
|
-
data: includesUnifiedResponse ? Buffer.from(JSON.stringify({ response_id:
|
|
2732
|
+
data: includesUnifiedResponse ? Buffer.from(JSON.stringify({ response_id: responseId, sections })).toString('base64') : '',
|
|
2662
2733
|
},
|
|
2663
2734
|
contextInfo: {
|
|
2664
2735
|
...forward,
|
|
@@ -2679,106 +2750,96 @@ class AIRich extends BaseBuilder {
|
|
|
2679
2750
|
// the two calls expect different option shapes, so the fallback now only forwards `quoted`
|
|
2680
2751
|
// (the one option that clearly applies to both) instead of blindly spreading everything.
|
|
2681
2752
|
/** Build and send this AI-rich message. @param {string} jid Destination chat/group jid. @param {boolean} [skipImageFallback] Skip auto-resending inline images as a plain imageMessage. */
|
|
2682
|
-
async send(jid, {
|
|
2683
|
-
forwarded,
|
|
2684
|
-
notification,
|
|
2685
|
-
includesUnifiedResponse,
|
|
2686
|
-
includesSubmessages,
|
|
2687
|
-
skipImageFallback = false,
|
|
2688
|
-
nativeFallback = true,
|
|
2689
|
-
quoted,
|
|
2690
|
-
...options
|
|
2691
|
-
} = {}) {
|
|
2753
|
+
async send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages, skipImageFallback = false, quoted, messageId, ...options } = {}) {
|
|
2692
2754
|
const msg = await this.build({ forwarded, notification, includesUnifiedResponse, includesSubmessages, quoted, ...options });
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
// 1) Send real WhatsApp media first. addImage()/addVideo()/addInlineImage()
|
|
2703
|
-
// already populate this queue with resolved URLs/buffers.
|
|
2704
|
-
if (!skipImageFallback && this._mediaFallbacks.length) {
|
|
2705
|
-
const fallbacks = await waitAllPromises(this._mediaFallbacks);
|
|
2706
|
-
for (const item of fallbacks) {
|
|
2707
|
-
try {
|
|
2708
|
-
const media = Buffer.isBuffer(item.url) ? item.url : { url: item.url };
|
|
2709
|
-
const content = { [item.type]: media };
|
|
2710
|
-
if (item.caption) content.caption = item.caption;
|
|
2711
|
-
if (item.mimetype) content.mimetype = item.mimetype;
|
|
2712
|
-
if (item.fileName) content.fileName = item.fileName;
|
|
2713
|
-
sent.push(await this.#client.sendMessage(jid, content, sendOptions));
|
|
2714
|
-
} catch (err) {
|
|
2715
|
-
this.#client.logger?.warn?.(
|
|
2716
|
-
{ err, url: item.url, type: item.type },
|
|
2717
|
-
'AIRich native media fallback failed'
|
|
2718
|
-
);
|
|
2719
|
-
}
|
|
2755
|
+
|
|
2756
|
+
if (!skipImageFallback && this._inlineImages.length) {
|
|
2757
|
+
for (const { url, caption } of this._inlineImages) {
|
|
2758
|
+
try {
|
|
2759
|
+
await this.#client.sendMessage(jid, { image: { url }, caption }, quoted ? { quoted } : {});
|
|
2760
|
+
} catch (err) {
|
|
2761
|
+
// Vanz@Fix: don't let a fallback image failure block the actual rich card from sending
|
|
2762
|
+
this.#client.logger?.warn?.({ err, url }, 'inline image fallback failed, continuing with rich card');
|
|
2720
2763
|
}
|
|
2721
2764
|
}
|
|
2765
|
+
}
|
|
2722
2766
|
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
if (!sub) continue;
|
|
2728
|
-
|
|
2729
|
-
if (typeof sub.messageText === 'string' && sub.messageText.trim()) {
|
|
2730
|
-
const t = sub.messageText.trim();
|
|
2731
|
-
|
|
2732
|
-
// Media primitives already have a native media message above; don't emit
|
|
2733
|
-
// their internal placeholder text as a duplicate.
|
|
2734
|
-
if (
|
|
2735
|
-
t === '[ Video tidak dapat dimuat ]' ||
|
|
2736
|
-
t === '[ Postingan tidak dapat dimuat ]' ||
|
|
2737
|
-
t === '[ Produk tidak dapat dimuat ]' ||
|
|
2738
|
-
t === '[ Sedang diproses... ]'
|
|
2739
|
-
) continue;
|
|
2740
|
-
|
|
2741
|
-
lines.push(t);
|
|
2742
|
-
continue;
|
|
2743
|
-
}
|
|
2767
|
+
// Vanz@Add --- pin our own messageId (instead of letting relayMessage mint one internally)
|
|
2768
|
+
// so we know exactly which id was sent, and stash it as _lastMessageKey. That's what lets
|
|
2769
|
+
// sendEdit() be called with no args afterwards and still know which message to patch.
|
|
2770
|
+
messageId = messageId || generateMessageIDV2();
|
|
2744
2771
|
|
|
2745
|
-
|
|
2746
|
-
const blocks = sub.codeMetadata.codeBlocks ?? [];
|
|
2747
|
-
const code = Array.isArray(blocks)
|
|
2748
|
-
? blocks.map((b) => typeof b === 'string' ? b : (b?.value ?? '')).join('')
|
|
2749
|
-
: String(blocks);
|
|
2750
|
-
lines.push('```' + (sub.codeMetadata.codeLanguage || '') + '\\n' + code + '\\n```');
|
|
2751
|
-
continue;
|
|
2752
|
-
}
|
|
2772
|
+
await this.#client.relayMessage(jid, msg, { messageId, ...options });
|
|
2753
2773
|
|
|
2754
|
-
|
|
2755
|
-
const rows = sub.tableMetadata.rows;
|
|
2756
|
-
if (Array.isArray(rows)) {
|
|
2757
|
-
lines.push(rows.map((row) => {
|
|
2758
|
-
const cells = Array.isArray(row) ? row : row?.cells;
|
|
2759
|
-
return Array.isArray(cells)
|
|
2760
|
-
? cells.map((c) => typeof c === 'string' ? c : (c?.text ?? c?.value ?? '')).join(' | ')
|
|
2761
|
-
: String(row);
|
|
2762
|
-
}).join('\\n'));
|
|
2763
|
-
}
|
|
2764
|
-
continue;
|
|
2765
|
-
}
|
|
2774
|
+
this._lastMessageKey = { remoteJid: jid, fromMe: true, id: messageId };
|
|
2766
2775
|
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2776
|
+
return { key: this._lastMessageKey, message: msg };
|
|
2777
|
+
}
|
|
2771
2778
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2779
|
+
/**
|
|
2780
|
+
* Build a `protocolMessage` (type EDIT) that patches an already-sent AIRich message in place.
|
|
2781
|
+
* @param {string} targetJid Chat the original message lives in.
|
|
2782
|
+
* @param {string} targetId `key.id` of the original message (the id `send()`/`sendEdit()` returned).
|
|
2783
|
+
* @param {object} [opts] Pass `{ msg }` to reuse an already-built content object instead of rebuilding via build().
|
|
2784
|
+
*/
|
|
2785
|
+
async buildEdit(targetJid, targetId, { msg, messageId, ...options } = {}) {
|
|
2786
|
+
const editedMessage = msg || (await this.build({ ...options }));
|
|
2787
|
+
|
|
2788
|
+
if (!editedMessage) {
|
|
2789
|
+
throw new Error('buildEdit: no message content to edit (build() returned nothing)');
|
|
2790
|
+
}
|
|
2776
2791
|
|
|
2777
|
-
|
|
2792
|
+
return generateWAMessageFromContent(
|
|
2793
|
+
targetJid,
|
|
2794
|
+
{
|
|
2795
|
+
protocolMessage: {
|
|
2796
|
+
key: {
|
|
2797
|
+
remoteJid: targetJid,
|
|
2798
|
+
fromMe: true,
|
|
2799
|
+
id: targetId,
|
|
2800
|
+
},
|
|
2801
|
+
type: 14, // MESSAGE_EDIT
|
|
2802
|
+
editedMessage,
|
|
2803
|
+
},
|
|
2804
|
+
},
|
|
2805
|
+
{ messageId: messageId || generateMessageIDV2(), ...options }
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
/**
|
|
2810
|
+
* Rebuild this AIRich message's current content and patch it into an already-sent message in place
|
|
2811
|
+
* (WA edits the bubble instead of showing a new one). With no args, edits the message from the last
|
|
2812
|
+
* send()/sendEdit() call — that's the flow `.addX(...); await rich.sendEdit();` relies on.
|
|
2813
|
+
* @param {string} [jid] Defaults to the jid from the last send()/sendEdit().
|
|
2814
|
+
* @param {string} [id] Defaults to the message id from the last send()/sendEdit().
|
|
2815
|
+
*/
|
|
2816
|
+
async sendEdit(jid, id, { msg, messageId, additionalNodes = [], ...options } = {}) {
|
|
2817
|
+
jid = jid ?? this._lastMessageKey?.remoteJid;
|
|
2818
|
+
id = id ?? this._lastMessageKey?.id;
|
|
2819
|
+
|
|
2820
|
+
if (!jid) {
|
|
2821
|
+
throw new Error('sendEdit: no jid — pass one explicitly, or call send() first');
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
if (!id) {
|
|
2825
|
+
throw new Error('sendEdit: no message id — pass one explicitly, or call send() first');
|
|
2778
2826
|
}
|
|
2779
2827
|
|
|
2780
|
-
|
|
2781
|
-
|
|
2828
|
+
const msgEdit = await this.buildEdit(jid, id, {
|
|
2829
|
+
msg,
|
|
2830
|
+
messageId: messageId || generateMessageIDV2(),
|
|
2831
|
+
...options,
|
|
2832
|
+
});
|
|
2833
|
+
|
|
2834
|
+
await this.#client.relayMessage(jid, msgEdit.message, {
|
|
2835
|
+
messageId: msgEdit.key.id,
|
|
2836
|
+
additionalNodes,
|
|
2837
|
+
});
|
|
2838
|
+
|
|
2839
|
+
// Vanz@Note --- deliberately NOT overwriting _lastMessageKey with msgEdit.key here: the
|
|
2840
|
+
// protocolMessage envelope has its own id, but the message the user actually sees (and the
|
|
2841
|
+
// one future sendEdit() calls need to keep patching) is still `id`/`jid` above.
|
|
2842
|
+
return msgEdit;
|
|
2782
2843
|
}
|
|
2783
2844
|
|
|
2784
2845
|
/** Tokenize `code` into `{ type, value }` spans for syntax highlighting. Covers JS/TS/Python/Java and more; unsupported languages fall back to a single plain-text token. */
|
|
@@ -3452,9 +3513,6 @@ class AIRich extends BaseBuilder {
|
|
|
3452
3513
|
if (!Array.isArray(arr) || !arr.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))) {
|
|
3453
3514
|
throw new TypeError('Table must be a nested array of strings');
|
|
3454
3515
|
}
|
|
3455
|
-
if (arr.length === 0 || arr[0].length === 0) {
|
|
3456
|
-
throw new TypeError('Table must contain a non-empty header row');
|
|
3457
|
-
}
|
|
3458
3516
|
|
|
3459
3517
|
const [header, ...rows] = arr;
|
|
3460
3518
|
|
|
@@ -3638,7 +3696,6 @@ export {
|
|
|
3638
3696
|
AIRich,
|
|
3639
3697
|
AIRich as AIVanzxy,
|
|
3640
3698
|
AIRich as LeafRich,
|
|
3641
|
-
AIRich as LeafReach,
|
|
3642
3699
|
AIRich as VanzxyAI,
|
|
3643
3700
|
AIRich as VanzxyRich,
|
|
3644
3701
|
Toolkit,
|
|
@@ -155,6 +155,11 @@ export class AIRich extends BaseBuilder {
|
|
|
155
155
|
addProduct(data?: Record<string, any>, options?: { resolveUrl?: boolean }): this;
|
|
156
156
|
addPost(data?: Record<string, any>, options?: { resolveUrl?: boolean }): this;
|
|
157
157
|
addTip(text: string): this;
|
|
158
|
+
addMetadata(text: string): this;
|
|
159
|
+
setResponseId(id: string): this;
|
|
160
|
+
refreshResponseId(): this;
|
|
161
|
+
setBotResponseId(id: string): this;
|
|
162
|
+
refreshBotResponseId(): this;
|
|
158
163
|
/** FOATextPrimitive — large heading text, distinct from addText()'s paragraph text. */
|
|
159
164
|
addHeading(text: string): this;
|
|
160
165
|
/** GenAIImagePrimitive — "ready" static image (preview + full-res), distinct from addImage()'s generation-style card. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vanzxy/baileys",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Enhanced Baileys fork by Vanzxy — based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./lib/index.js",
|