plogme 1.0.3 → 1.0.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.
@@ -2,7 +2,7 @@ import { proto } from '../../WAProto/index.js';
2
2
  import { makeLibSignalRepository } from '../Signal/libsignal.js';
3
3
  import { Browsers } from '../Utils/browser-utils.js';
4
4
  import logger from '../Utils/logger.js';
5
- const version = [2, 3000, 1040735178];
5
+ const version = [2, 3000, 1047412487];
6
6
  export const UNAUTHORIZED_CODES = [401, 403, 419];
7
7
  export const BIZ_BOT_SUPPORT_PAYLOAD = '{"version":1,"is_ai_message":true,"should_upload_client_logs":false,"should_show_system_message":false,"ticket_id":"7004947587700716","citation_items":[],"ticket_locale":"us"}';
8
8
  export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
@@ -5,7 +5,7 @@ import { proto } from '../../WAProto/index.js';
5
5
  import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
6
6
  import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
7
7
  import { getUrlInfo } from '../Utils/link-preview.js';
8
- import { prepareRichMenuMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareHtmlMessage } from '../Utils/rich-message-utils.js';
8
+ import { prepareRichMenuMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareHtmlMessage } from '../Utils/rich-message-utils.js';
9
9
  import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
10
10
  import { generateWebsitePreviewHtml, generateLinkPreviewHtml } from '../Utils/games/website-preview.js';
11
11
  import { isViewOnceMessage, extractViewOnceContent, getViewOnceMediaType, getViewOnceMediaContent, downloadViewOnceMedia, createRegularMessageFromViewOnce, parseViewOnceInfo } from '../Utils/view-once-utils.js';
@@ -2157,6 +2157,13 @@ export const makeMessagesSocket = (config) => {
2157
2157
  delete content.ai;
2158
2158
  }
2159
2159
 
2160
+ if ('album' in content) {
2161
+ if (!Array.isArray(content.album) || content.album.length < 2) {
2162
+ throw new Boom('Album requires at least two image or video items', { statusCode: 400 });
2163
+ }
2164
+ fullMsg.message.messageContextInfo ||= {};
2165
+ fullMsg.message.messageContextInfo.messageSecret ||= randomBytes(32);
2166
+ }
2160
2167
  await relayMessage(jid, fullMsg.message, {
2161
2168
  messageId: fullMsg.key.id,
2162
2169
  useCachedGroupMetadata: options.useCachedGroupMetadata,
@@ -2175,7 +2182,7 @@ export const makeMessagesSocket = (config) => {
2175
2182
 
2176
2183
  if ('album' in content) {
2177
2184
  const { delayMs = 1500 } = options;
2178
- for (const albumMedia of content.album) {
2185
+ for (const [messageIndex, albumMedia] of content.album.entries()) {
2179
2186
  const albumMsg = await generateWAMessage(jid, albumMedia, {
2180
2187
  logger,
2181
2188
  userJid,
@@ -2198,7 +2205,8 @@ export const makeMessagesSocket = (config) => {
2198
2205
  // WhatsApp album child messages use association type 1.
2199
2206
  // The generated MEDIA_ALBUM enum value (63) is a message
2200
2207
  // category, not the child-association wire value.
2201
- associationType: 1
2208
+ associationType: 1,
2209
+ messageIndex
2202
2210
  };
2203
2211
  await relayMessage(jid, albumMsg.message, {
2204
2212
  messageId: albumMsg.key.id,
@@ -2252,7 +2260,7 @@ export const makeMessagesSocket = (config) => {
2252
2260
  */
2253
2261
  socket.sendRichText = async (jid, content = {}, options = {}) => {
2254
2262
  if (!jid) throw new Boom('sendRichText requires a target JID', { statusCode: 400 });
2255
- const wrapped = prepareRichTextMessage(content);
2263
+ const wrapped = content.copyText ? prepareRichQuoteMessage(content) : prepareRichTextMessage(content);
2256
2264
  const fullMsg = await generateWAMessageFromContent(jid, wrapped, {
2257
2265
  logger,
2258
2266
  userJid: authState.creds.me?.id,
@@ -2271,6 +2279,32 @@ export const makeMessagesSocket = (config) => {
2271
2279
  }
2272
2280
  return fullMsg;
2273
2281
  };
2282
+ /** Sends ordinary Markdown/text with a GenAI COPY_TO_CLIPBOARD action; no quote syntax is required. */
2283
+ socket.sendRichTextCopy = async (jid, content = {}, options = {}) => {
2284
+ if (!jid) throw new Boom('sendRichTextCopy requires a target JID', { statusCode: 400 });
2285
+ if (!content.copyText) throw new Boom('sendRichTextCopy requires copyText content', { statusCode: 400 });
2286
+ const wrapped = prepareRichQuoteMessage(content);
2287
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2288
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2289
+ return fullMsg;
2290
+ };
2291
+ /** Sends Markdown text containing blockquotes in a forwarded GenAI rich response. */
2292
+ socket.sendMarkdownQuote = async (jid, content = {}, options = {}) => {
2293
+ if (!jid) throw new Boom('sendMarkdownQuote requires a target JID', { statusCode: 400 });
2294
+ const wrapped = prepareRichQuoteMessage(content);
2295
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2296
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2297
+ return fullMsg;
2298
+ };
2299
+ /** Sends Markdown blockquotes followed by a GenAI COPY_TO_CLIPBOARD action. */
2300
+ socket.sendQuoteCopy = async (jid, content = {}, options = {}) => {
2301
+ if (!jid) throw new Boom('sendQuoteCopy requires a target JID', { statusCode: 400 });
2302
+ if (!content.copyText) throw new Boom('sendQuoteCopy requires copyText content', { statusCode: 400 });
2303
+ const wrapped = prepareRichQuoteMessage(content);
2304
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2305
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2306
+ return fullMsg;
2307
+ };
2274
2308
  /**
2275
2309
  * Sends an image inside a forwarded GenAI rich response envelope.
2276
2310
  */
@@ -2340,6 +2374,42 @@ export const makeMessagesSocket = (config) => {
2340
2374
  }
2341
2375
  return fullMsg;
2342
2376
  };
2377
+ /** Sends a rich response with experimental BotInfrastructureDiagnostics metadata. */
2378
+ socket.sendBotDiagnostics = async (jid, content = {}, options = {}) => {
2379
+ if (!jid) throw new Boom('sendBotDiagnostics requires a target JID', { statusCode: 400 });
2380
+ const { text = 'Bot diagnostics test', botBackend = 0, toolsUsed = [], isThinking = false, botJid = '867051314767696@bot' } = content;
2381
+ const wrapped = {
2382
+ messageContextInfo: { botMetadata: { botInfrastructureDiagnostics: { botBackend, toolsUsed, isThinking } } },
2383
+ botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
2384
+ };
2385
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2386
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2387
+ return fullMsg;
2388
+ };
2389
+ /** Sends a rich response with experimental BotCommandMetadata. */
2390
+ socket.sendBotCommand = async (jid, content = {}, options = {}) => {
2391
+ if (!jid) throw new Boom('sendBotCommand requires a target JID', { statusCode: 400 });
2392
+ const { text = 'Bot command test', commandName = '', commandDescription = '', commandPrompt = '', botJid = '867051314767696@bot' } = content;
2393
+ const wrapped = {
2394
+ messageContextInfo: { botMetadata: { commandMetadata: { commandName, commandDescription, commandPrompt } } },
2395
+ botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
2396
+ };
2397
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2398
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2399
+ return fullMsg;
2400
+ };
2401
+ /** Sends a rich response with experimental BotResolvedToolCallMetadata. */
2402
+ socket.sendBotToolResult = async (jid, content = {}, options = {}) => {
2403
+ if (!jid) throw new Boom('sendBotToolResult requires a target JID', { statusCode: 400 });
2404
+ const { text = 'Bot tool result test', toolCallId = `tool-${Date.now()}`, resolutionData, resolutionDataSerialized, botJid = '867051314767696@bot' } = content;
2405
+ const wrapped = {
2406
+ messageContextInfo: { botMetadata: { resolvedToolCallMetadata: { toolCallId, resolutionDataSerialized: resolutionDataSerialized ?? JSON.stringify(resolutionData ?? {}) } } },
2407
+ botForwardedMessage: { message: { richResponseMessage: { messageType: 1, submessages: [{ messageType: 2, messageText: text }], contextInfo: { isForwarded: true, forwardingScore: 1, forwardedAiBotMessageInfo: { botJid }, forwardOrigin: 4 } } } }
2408
+ };
2409
+ const fullMsg = await generateWAMessageFromContent(jid, wrapped, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
2410
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
2411
+ return fullMsg;
2412
+ };
2343
2413
  socket.sendStatus = async (content, options = {}) => {
2344
2414
  const statusJidList = await resolveStatusRecipients(options.statusJidList || content?.statusJidList);
2345
2415
  return socket.sendMessage(STATUS_JID, {
@@ -2534,6 +2604,29 @@ export const makeMessagesSocket = (config) => {
2534
2604
  socket.getViewOnceInfo = (message) => parseViewOnceInfo(message);
2535
2605
 
2536
2606
 
2607
+ /**
2608
+ * Sends an experimental WhatsApp album. The parent album header and each
2609
+ * image/video child are relayed separately and associated by parent key.
2610
+ * Accepts [{ image: ... }, { video: ... }] or [{ type: 'image', data: ... }].
2611
+ */
2612
+ socket.sendAlbumMessage = async (jid, medias = [], options = {}) => {
2613
+ if (!jid) throw new Boom('sendAlbumMessage requires a target JID', { statusCode: 400 });
2614
+ if (!Array.isArray(medias) || medias.length < 2) {
2615
+ throw new Boom('sendAlbumMessage requires at least two media items', { statusCode: 400 });
2616
+ }
2617
+ const album = medias.map((media, index) => {
2618
+ const normalized = media?.type && media?.data
2619
+ ? { [media.type]: media.data }
2620
+ : { ...media };
2621
+ if (index === 0 && options.caption && !normalized.caption) {
2622
+ normalized.caption = options.caption;
2623
+ }
2624
+ return normalized;
2625
+ });
2626
+ return socket.sendMessage(jid, { album }, options);
2627
+ };
2628
+
2629
+
2537
2630
  /**
2538
2631
  * Sends an HTML message — renders raw HTML inside the chat bubble.
2539
2632
  * Uses FOAHtmlPrimitiveDemoDONOTUSE for full HTML/CSS/JS rendering.
@@ -1016,6 +1016,33 @@ export const generateWAMessageContent = async (message, options) => {
1016
1016
  else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
1017
1017
  m.requestPhoneNumberMessage = {};
1018
1018
  }
1019
+ else if (hasNonNullishProperty(message, 'chatTheme')) {
1020
+ const theme = message.chatTheme || {};
1021
+ const themeSetting = {};
1022
+ if (theme.animatedWallpaper) {
1023
+ const wallpaper = theme.animatedWallpaper;
1024
+ themeSetting.animatedWallpaper = proto.Message.ChatAnimatedWallpaper.fromObject({
1025
+ animatedWallpaperId: wallpaper.id || wallpaper.animatedWallpaperId,
1026
+ dimLevel: wallpaper.dimLevel ?? (wallpaper.opacity != null ? wallpaper.opacity / 100 : 0)
1027
+ });
1028
+ }
1029
+ if (Object.keys(themeSetting).length) {
1030
+ m.protocolMessage = {
1031
+ type: proto.Message.ProtocolMessage.Type.CHAT_THEME_SETTING,
1032
+ chatThemeSetting: proto.Message.ChatThemeSetting.fromObject(themeSetting)
1033
+ };
1034
+ }
1035
+ }
1036
+ else if (hasNonNullishProperty(message, 'newsletterFollowerInvite') ||
1037
+ hasNonNullishProperty(message, 'newsletterFollowerInviteMessage') ||
1038
+ hasNonNullishProperty(message, 'newsletterFollowerInviteMessageV2')) {
1039
+ const isV2 = hasNonNullishProperty(message, 'newsletterFollowerInviteMessageV2');
1040
+ const invite = isV2
1041
+ ? message.newsletterFollowerInviteMessageV2
1042
+ : (message.newsletterFollowerInvite ?? message.newsletterFollowerInviteMessage);
1043
+ const field = isV2 ? 'newsletterFollowerInviteMessageV2' : 'newsletterFollowerInviteMessage';
1044
+ m = { [field]: proto.Message.NewsletterFollowerInviteMessage.fromObject(invite) };
1045
+ }
1019
1046
  else if (hasNonNullishProperty(message, 'limitSharing')) {
1020
1047
  m.protocolMessage = {
1021
1048
  type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
@@ -1033,6 +1060,12 @@ export const generateWAMessageContent = async (message, options) => {
1033
1060
  m.audioMessage.backgroundArgb = await assertColor(options.backgroundColor);
1034
1061
  }
1035
1062
  }
1063
+ if (m.stickerMessage && hasNonNullishProperty(message, 'stickerAudio')) {
1064
+ const audioPrepared = await prepareWAMessageMedia({ audio: message.stickerAudio, ptt: true }, options);
1065
+ if (audioPrepared?.audioMessage) {
1066
+ m.stickerMessage.audioMessage = audioPrepared.audioMessage;
1067
+ }
1068
+ }
1036
1069
  // Lia@Changes 30-01-26 --- Add interactive messages (buttonsMessage, listMessage, interactiveMessage, templateMessage, and carouselMessage)
1037
1070
  if (hasNonNullishProperty(message, 'buttons')) {
1038
1071
  const buttonsMessage = {
@@ -1222,18 +1255,21 @@ export const generateWAMessageContent = async (message, options) => {
1222
1255
  throw new Boom('Invalid media type for carousel card', { statusCode: 400 });
1223
1256
  }
1224
1257
  const carouselCard = {
1225
- nativeFlowMessage: prepareNativeFlowButtons(card.nativeFlow ? card : [])
1258
+ nativeFlowMessage: prepareNativeFlowButtons({
1259
+ ...card,
1260
+ nativeFlow: card.nativeFlow || card.buttons || []
1261
+ }),
1262
+ header: {
1263
+ title: card.title || '',
1264
+ subtitle: card.subtitle || '',
1265
+ hasMediaAttachment: isValidHeader
1266
+ }
1226
1267
  };
1227
1268
  if (hasOptionalProperty(card, 'text')) {
1228
1269
  carouselCard.body = { text: card.text };
1229
1270
  }
1230
1271
  else {
1231
1272
  if (hasOptionalProperty(card, 'caption')) {
1232
- carouselCard.header = {
1233
- title: card.title || '',
1234
- subtitle: card.subtitle || '',
1235
- hasMediaAttachment: isValidHeader
1236
- };
1237
1273
  carouselCard.body = { text: card.caption };
1238
1274
  }
1239
1275
  if (hasOptionalProperty(card, 'thumbnail') && !!card.thumbnail) {
@@ -1402,10 +1438,9 @@ export const generateWAMessageContent = async (message, options) => {
1402
1438
  const messageType = Object.keys(m)[0];
1403
1439
  const key = m[messageType];
1404
1440
  const mediaSpoiler = ['imageMessage', 'videoMessage', 'documentMessage', 'stickerMessage'].includes(messageType);
1405
- // View-once is the only broadly supported WhatsApp envelope that
1406
- // withholds the media preview until the recipient opens/downloads it.
1407
- // Native spoiler metadata remains available as an explicit opt-in.
1408
- const mediaSpoilerMode = message.mediaSpoilerMode || options?.mediaSpoilerMode || 'viewOnce';
1441
+ // Native media spoilers use contextInfo.isSpoiler. View-once remains an
1442
+ // explicit compatibility fallback for clients that do not render it.
1443
+ const mediaSpoilerMode = message.mediaSpoilerMode || options?.mediaSpoilerMode || 'native';
1409
1444
  if (mediaSpoiler && mediaSpoilerMode === 'viewOnce') {
1410
1445
  m = { viewOnceMessage: { message: m } };
1411
1446
  }
@@ -1416,7 +1451,8 @@ export const generateWAMessageContent = async (message, options) => {
1416
1451
  else if (key) {
1417
1452
  key.contextInfo = { isSpoiler: true };
1418
1453
  }
1419
- m = { spoilerMessage: { message: m } };
1454
+ // `spoilerMessage` is not a field in WAProto.Message. The native
1455
+ // representation is the media message's contextInfo.isSpoiler bit.
1420
1456
  }
1421
1457
  else if (key && typeof key.text === 'string') {
1422
1458
  const nativeSpoiler = message.spoilerMode === 'native' || options?.spoilerMode === 'native';
@@ -138,6 +138,17 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
138
138
  }
139
139
  }
140
140
  const content = normalizeMessageContent(message.message);
141
+ if (content?.acp2SettingMessage) {
142
+ const acp2Setting = message.messageContextInfo?.acp2Setting;
143
+ if (acp2Setting) {
144
+ Object.assign(chat, {
145
+ acp2Enabled: acp2Setting.enabled || false,
146
+ acp2SettingTimestamp: toNumber(acp2Setting.settingTimestamp) || toNumber(message.messageTimestamp),
147
+ acp2Trigger: acp2Setting.trigger,
148
+ acp2InitiatedByMe: acp2Setting.initiatedByMe || false
149
+ });
150
+ }
151
+ }
141
152
  // unarchive chat if it's a real message, or someone reacted to our message
142
153
  // and we've the unarchive chats setting on
143
154
  if ((isRealMsg || content?.reactionMessage?.key?.fromMe) && accountSettings?.unarchiveChats) {
@@ -579,4 +590,4 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
579
590
  ev.emit('chats.update', [chat]);
580
591
  }
581
592
  };
582
- export default processMessage;
593
+ export default processMessage;
@@ -494,6 +494,37 @@ export const prepareRichTextMessage = (options = {}) => {
494
494
  return wrapToBotForwardedMessage(richResponseMessage);
495
495
  };
496
496
 
497
+ /** Builds Markdown text with an optional GenAI COPY_TO_CLIPBOARD action section. */
498
+ export const prepareRichQuoteMessage = (options = {}) => {
499
+ const { text = '', copyText, copyLabel = copyText, alignment = 'END' } = options;
500
+ const sections = [{
501
+ __typename: 'GenAIUnifiedResponseSection',
502
+ view_model: {
503
+ __typename: 'GenAISingleLayoutViewModel',
504
+ primitive: { __typename: 'GenAIMarkdownTextUXPrimitive', text: String(text), inline_entities: [] },
505
+ },
506
+ }];
507
+ if (copyText) {
508
+ sections.push({
509
+ __typename: 'GenAIUnifiedResponseSection',
510
+ view_model: {
511
+ __typename: 'GenAIAddonActionLayoutViewModel',
512
+ addon_action_type: 'COPY_TO_CLIPBOARD',
513
+ addon_action_alignment: alignment,
514
+ primitives: [{ __typename: 'GenAIMarkdownTextUXPrimitive', text: String(copyLabel || copyText), inline_entities: [] }],
515
+ },
516
+ });
517
+ }
518
+ const unified = { response_id: randomUUID(), sections };
519
+ const richResponseMessage = proto.AIRichResponseMessage.create({
520
+ submessages: [],
521
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
522
+ unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
523
+ contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
524
+ });
525
+ return wrapToBotForwardedMessage(richResponseMessage);
526
+ };
527
+
497
528
  /**
498
529
  * Builds a GenAI rich image message — an image rendered inside a forwarded rich response.
499
530
  * Uses GenAIImagePrimitive with preview and full image variants.
@@ -939,4 +970,4 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
939
970
  message: { richResponseMessage }
940
971
  }
941
972
  });
942
- //# sourceMappingURL=rich-message-utils.js.map
973
+ //# sourceMappingURL=rich-message-utils.js.map
package/lib/index.d.ts CHANGED
@@ -213,21 +213,45 @@ export interface RelayMessageOptions {
213
213
  /** Retry resend target; requires a device JID and retry count. */
214
214
  participants?: { jid: string; count: number };
215
215
  retryParticipants?: { jid: string; count: number };
216
- /** Keep only the target's primary device. */
216
+ /** Keep only the target's primary device in supported private-chat fan-out paths; not encryption. */
217
217
  isSecret?: boolean;
218
- /** Skip the target's linked devices. */
218
+ /** Skip the target's linked devices in supported private-chat fan-out paths; enforcement is client-dependent. */
219
219
  protected?: boolean;
220
- /** Keep only the sender's own devices. */
220
+ /** Keep only the sender's own devices in supported private-chat fan-out paths. */
221
221
  me?: boolean;
222
222
  [key: string]: unknown;
223
223
  }
224
224
 
225
+ export interface AlbumMediaInput {
226
+ image?: unknown;
227
+ video?: unknown;
228
+ caption?: string;
229
+ [key: string]: unknown;
230
+ }
231
+
232
+ export interface AnimatedWallpaperInput {
233
+ id?: string;
234
+ animatedWallpaperId?: string;
235
+ dimLevel?: number;
236
+ opacity?: number;
237
+ }
238
+
225
239
  export interface WASocket {
226
240
  sendMessage(jid: string | string[], content: StatusContent | GroupStatusContent | Record<string, unknown>, options?: Partial<StatusOptions> & Record<string, unknown>): Promise<unknown>;
241
+ /** Send at least two image/video items as an experimental WhatsApp album. */
242
+ sendAlbumMessage(jid: string, medias: AlbumMediaInput[], options?: Record<string, unknown>): Promise<unknown>;
243
+ /** Update the connected account's WhatsApp About/profile status. */
244
+ updateProfileStatus(status: string): Promise<void>;
245
+ /** Update the connected account's profile name. */
246
+ updateProfileName(name: string): Promise<void>;
247
+ /** Set or clear the connected account's own custom label in a group. */
248
+ updateMemberLabel(groupJid: string, memberLabel: string): Promise<unknown>;
227
249
  /** Relay a prepared message with optional recipient/device-scoping compatibility controls. */
228
250
  relayMessage(jid: string, message: Record<string, unknown>, options?: RelayMessageOptions): Promise<unknown>;
229
251
  /** Send an experimental Meta AI-style rich menu with image, card buttons, and an optional URL footer. */
230
252
  richMenu(jid: string, content?: RichMenuContent, options?: Record<string, unknown>): Promise<unknown>;
253
+ /** Send raw HTML through the experimental WhatsApp HTML primitive. */
254
+ sendHtmlMessage(jid: string, content: { html: string; trustedSources?: string[] }, options?: Record<string, unknown>): Promise<unknown>;
231
255
  /** Post a personal status using explicit viewers or a configured contact source/provider. */
232
256
  sendStatus(content: Omit<StatusContent, 'statusJidList'>, options?: Partial<StatusOptions> & { statusJidList?: string[] }): Promise<unknown>;
233
257
  /** Publish a status and create status-mention references for the supplied users or groups. */
@@ -238,6 +262,18 @@ export interface WASocket {
238
262
  sendWhatsAppFlow(jid: string, flow: { flowId: string; flowToken: string; cta?: string; action?: string; actionPayload?: Record<string, unknown>; mode?: string; flowMessageVersion?: string | number; metadata?: Record<string, unknown>; text?: string; footer?: string; image?: unknown; caption?: string; nativeFlowName?: string }, options?: Record<string, unknown>): Promise<unknown>;
239
263
  /** Send a rich native-flow URL CTA that opens a hosted WebView/Mini App. */
240
264
  sendRichWebview(jid: string, content: { text?: string; title?: string; footer?: string; image?: unknown; caption?: string; buttonText?: string; url: string; useWebview?: boolean; toast?: string; [key: string]: unknown }, options?: Record<string, unknown>): Promise<unknown>;
265
+ /** Send a rich response with experimental bot infrastructure diagnostics metadata. */
266
+ sendBotDiagnostics(jid: string, content?: { text?: string; botBackend?: number; toolsUsed?: string[]; isThinking?: boolean; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
267
+ /** Send a rich response with experimental bot command metadata. */
268
+ sendBotCommand(jid: string, content?: { text?: string; commandName?: string; commandDescription?: string; commandPrompt?: string; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
269
+ /** Send a rich response with experimental resolved tool-call metadata. */
270
+ sendBotToolResult(jid: string, content?: { text?: string; toolCallId?: string; resolutionData?: unknown; resolutionDataSerialized?: string; botJid?: string }, options?: Record<string, unknown>): Promise<unknown>;
271
+ /** Send Markdown text containing blockquotes in a forwarded GenAI rich response. */
272
+ sendMarkdownQuote(jid: string, content?: { text?: string; copyText?: string; copyLabel?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
273
+ /** Send Markdown blockquotes followed by a GenAI COPY_TO_CLIPBOARD action. */
274
+ sendQuoteCopy(jid: string, content: { text?: string; copyText: string; copyLabel?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
275
+ /** Send ordinary Markdown/text followed by a GenAI COPY_TO_CLIPBOARD action. */
276
+ sendRichTextCopy(jid: string, content: { text?: string; copyText: string; copyLabel?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
241
277
  /** Send a native AI image/video generation card with a GENERATING or READY state. */
242
278
  sendRichGeneration(jid: string, content?: RichGenerationContent, quoted?: unknown, options?: Record<string, unknown>): Promise<RichGenerationResult>;
243
279
  /** Edit an existing AI generation card in place using WhatsApp's type-14 edit protocol. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plogme",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Production-ready Baileys fork \u2689 with AI groups, Meta AI prompting, safe compositing fallbacks, rich responses, interactive messages, albums, newsletters, and communities \u2014 without antiban wrappers.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://pair.crysnovax.link"
17
+ "url": "https://github.com/crysnovax/bailey"
18
18
  },
19
19
  "files": [
20
20
  "lib/**/*",