plogme 2.1.1 → 2.2.0

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.
Files changed (148) hide show
  1. package/README.md +115 -0
  2. package/WAProto/WAProto.proto +12 -0
  3. package/WAProto/index.d.ts +12 -0
  4. package/WAProto/index.js +12 -0
  5. package/engine-requirements.js +12 -0
  6. package/lib/Defaults/ban-checker.js +12 -0
  7. package/lib/Defaults/index.js +12 -0
  8. package/lib/Signal/Group/ciphertext-message.js +12 -0
  9. package/lib/Signal/Group/group-session-builder.js +12 -0
  10. package/lib/Signal/Group/group_cipher.js +12 -0
  11. package/lib/Signal/Group/index.js +12 -0
  12. package/lib/Signal/Group/keyhelper.js +12 -0
  13. package/lib/Signal/Group/sender-chain-key.js +12 -0
  14. package/lib/Signal/Group/sender-key-distribution-message.js +12 -0
  15. package/lib/Signal/Group/sender-key-message.js +12 -0
  16. package/lib/Signal/Group/sender-key-name.js +12 -0
  17. package/lib/Signal/Group/sender-key-record.js +12 -0
  18. package/lib/Signal/Group/sender-key-state.js +12 -0
  19. package/lib/Signal/Group/sender-message-key.js +12 -0
  20. package/lib/Signal/libsignal.js +12 -0
  21. package/lib/Signal/lid-mapping.js +12 -0
  22. package/lib/Socket/Client/index.js +12 -0
  23. package/lib/Socket/Client/types.js +12 -0
  24. package/lib/Socket/Client/websocket.js +12 -0
  25. package/lib/Socket/aigroups.js +12 -0
  26. package/lib/Socket/ban-checker.js +12 -0
  27. package/lib/Socket/business.js +12 -0
  28. package/lib/Socket/chats.js +12 -0
  29. package/lib/Socket/communities.js +12 -0
  30. package/lib/Socket/graphql.js +12 -0
  31. package/lib/Socket/groups.js +12 -0
  32. package/lib/Socket/index.js +12 -0
  33. package/lib/Socket/interactive-handler.js +12 -0
  34. package/lib/Socket/interop.js +12 -0
  35. package/lib/Socket/managed-account.js +12 -0
  36. package/lib/Socket/messages-recv.js +12 -0
  37. package/lib/Socket/messages-send.js +309 -6
  38. package/lib/Socket/mex.js +12 -0
  39. package/lib/Socket/newsletter.js +12 -0
  40. package/lib/Socket/privacy.js +12 -0
  41. package/lib/Socket/registration.js +12 -0
  42. package/lib/Socket/socket.js +12 -0
  43. package/lib/Socket/username.js +12 -0
  44. package/lib/Store/index.js +12 -0
  45. package/lib/Store/make-cache-manager-store.js +12 -0
  46. package/lib/Store/make-in-memory-store.js +12 -0
  47. package/lib/Store/make-ordered-dictionary.js +12 -0
  48. package/lib/Store/object-repository.js +12 -0
  49. package/lib/Types/Auth.js +12 -0
  50. package/lib/Types/Bussines.js +12 -0
  51. package/lib/Types/Call.js +12 -0
  52. package/lib/Types/Chat.js +12 -0
  53. package/lib/Types/Contact.js +12 -0
  54. package/lib/Types/Events.js +12 -0
  55. package/lib/Types/GroupMetadata.js +12 -0
  56. package/lib/Types/Label.js +12 -0
  57. package/lib/Types/LabelAssociation.js +12 -0
  58. package/lib/Types/Message.js +12 -0
  59. package/lib/Types/Mex.js +12 -0
  60. package/lib/Types/Product.js +12 -0
  61. package/lib/Types/RichType.js +12 -0
  62. package/lib/Types/Signal.js +12 -0
  63. package/lib/Types/Socket.js +12 -0
  64. package/lib/Types/State.js +12 -0
  65. package/lib/Types/USync.js +12 -0
  66. package/lib/Types/index.js +12 -0
  67. package/lib/Utils/auth-utils.js +12 -0
  68. package/lib/Utils/bot-capabilities.js +12 -0
  69. package/lib/Utils/bot-planning-replay.js +12 -0
  70. package/lib/Utils/browser-utils.js +12 -0
  71. package/lib/Utils/business.js +12 -0
  72. package/lib/Utils/c2582.js +144 -0
  73. package/lib/Utils/channel-policy.js +12 -0
  74. package/lib/Utils/chat-utils.js +12 -0
  75. package/lib/Utils/companion-reg-client-utils.js +12 -0
  76. package/lib/Utils/consumer-application.js +12 -0
  77. package/lib/Utils/crypto.js +12 -0
  78. package/lib/Utils/decode-wa-message.js +12 -0
  79. package/lib/Utils/event-buffer.js +12 -0
  80. package/lib/Utils/games/miniapp.js +12 -0
  81. package/lib/Utils/games/slot-machine.js +12 -0
  82. package/lib/Utils/games/website-preview.js +12 -0
  83. package/lib/Utils/generics.js +12 -0
  84. package/lib/Utils/group-history.js +12 -0
  85. package/lib/Utils/history.js +12 -0
  86. package/lib/Utils/identity-change-handler.js +12 -0
  87. package/lib/Utils/index.js +13 -0
  88. package/lib/Utils/jid-display-normalization.js +12 -0
  89. package/lib/Utils/link-preview.js +12 -0
  90. package/lib/Utils/logger.js +12 -0
  91. package/lib/Utils/lt-hash.js +12 -0
  92. package/lib/Utils/make-mutex.js +12 -0
  93. package/lib/Utils/message-composer.js +18 -1
  94. package/lib/Utils/message-inspect.js +12 -0
  95. package/lib/Utils/message-retry-manager.js +12 -0
  96. package/lib/Utils/messages-media.js +12 -0
  97. package/lib/Utils/messages.js +77 -4
  98. package/lib/Utils/meta-ai-msmsg.js +12 -0
  99. package/lib/Utils/meta-compositing.js +12 -0
  100. package/lib/Utils/native-flow.js +12 -0
  101. package/lib/Utils/noise-handler.js +12 -0
  102. package/lib/Utils/offline-node-processor.js +12 -0
  103. package/lib/Utils/pre-key-manager.js +12 -0
  104. package/lib/Utils/process-message.js +12 -0
  105. package/lib/Utils/reporting-utils.js +12 -0
  106. package/lib/Utils/rich-message-utils.js +299 -9
  107. package/lib/Utils/signal.js +12 -0
  108. package/lib/Utils/source-grep.js +12 -0
  109. package/lib/Utils/stanza-ack.js +12 -0
  110. package/lib/Utils/sync-action-utils.js +12 -0
  111. package/lib/Utils/tc-token-utils.js +12 -0
  112. package/lib/Utils/use-multi-file-auth-state.js +12 -0
  113. package/lib/Utils/use-single-file-auth-state.js +12 -0
  114. package/lib/Utils/use-sqlite-auth-state.js +12 -0
  115. package/lib/Utils/validate-connection.js +12 -0
  116. package/lib/Utils/view-once-utils.js +12 -0
  117. package/lib/Utils/voip-rekey.js +12 -0
  118. package/lib/Utils/welcome-flow.js +12 -0
  119. package/lib/WABinary/constants.js +12 -0
  120. package/lib/WABinary/decode.js +12 -0
  121. package/lib/WABinary/encode.js +12 -0
  122. package/lib/WABinary/generic-utils.js +12 -0
  123. package/lib/WABinary/index.js +12 -0
  124. package/lib/WABinary/jid-utils.js +12 -0
  125. package/lib/WABinary/types.js +12 -0
  126. package/lib/WAM/BinaryInfo.js +12 -0
  127. package/lib/WAM/constants.js +12 -0
  128. package/lib/WAM/encode.js +12 -0
  129. package/lib/WAM/index.js +12 -0
  130. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +12 -0
  131. package/lib/WAUSync/Protocols/USyncContactProtocol.js +12 -0
  132. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +12 -0
  133. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -0
  134. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +12 -0
  135. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +12 -0
  136. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +12 -0
  137. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +12 -0
  138. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +12 -0
  139. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +12 -0
  140. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +12 -0
  141. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +12 -0
  142. package/lib/WAUSync/Protocols/index.js +12 -0
  143. package/lib/WAUSync/USyncQuery.js +12 -0
  144. package/lib/WAUSync/USyncUser.js +12 -0
  145. package/lib/WAUSync/index.js +12 -0
  146. package/lib/index.d.ts +57 -2
  147. package/lib/index.js +12 -0
  148. package/package.json +9 -2
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/interactive-handler.js
5
+ * About: Interactive handler module for the Plogme WhatsApp protocol client.
6
+ * Important exports: Baron
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { randomBytes } from 'crypto';
2
14
  import { proto } from '../../WAProto/index.js';
3
15
  import {
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/interop.js
5
+ * About: Interop module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeInteropSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } from '../WABinary/index.js';
2
14
  import { executeWMexQuery } from './mex.js';
3
15
 
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/managed-account.js
5
+ * About: Managed account module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeManagedAccountSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { executeWMexQuery } from './mex.js';
2
14
 
3
15
  const MANAGED_ACCOUNT_MEX_IDS = {
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/messages-recv.js
5
+ * About: Messages recv module for the Plogme WhatsApp protocol client.
6
+ * Important exports: buildGroupCallStanza, buildGroupCallCancelStanza, makeMessagesRecvSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import NodeCache from '@cacheable/node-cache';
2
14
  import { Boom } from '@hapi/boom';
3
15
  import { randomBytes } from 'crypto';
@@ -1,9 +1,21 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/messages-send.js
5
+ * About: Messages send module for the Plogme WhatsApp protocol client.
6
+ * Important exports: normalizeStatusJidList, makeMessagesSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import NodeCache from '@cacheable/node-cache';
2
14
  import { Boom } from '@hapi/boom';
3
15
  import { randomBytes, randomUUID } from 'crypto';
4
16
  import { proto } from '../../WAProto/index.js';
5
17
  import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
6
- import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, generateWAMessageFromImagePoll, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
18
+ import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, generateWAMessageFromImagePoll, generateWAMessageFromLivePhoto, getStatusCodeForMediaRetry, makeWhatsAppFlowButton, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
7
19
  import { getUrlInfo } from '../Utils/link-preview.js';
8
20
  import { prepareRichMenuMessage, prepareA2UIMessage, prepareA2UICommandMenu, prepareAIRichCommandMenu, prepareSocialEntityMessage, prepareInstagramProfileMessage, prepareRichResponseMessage, prepareRichGenerationMessage, prepareCopyToClipboardMessage, prepareRichTextMessage, prepareRichQuoteMessage, prepareRichImageMessage, prepareRichLinkMessage, prepareSocialProfileMessage, prepareUnifiedResponseMessage, prepareRichMapMessage, prepareBotPromptSuggestionsMessage, prepareBotSourcesMessage, prepareRichDynamicMediaMessage, prepareBotPttTranscriptMessage, prepareGridImageMessage, prepareVerticalAlbumMessage, prepareVideoGridMessage, prepareHtmlMessage, prepareRichHtmlMessage, buildRichLabelMessage, attachBotVerificationProofs, hasVerifiableProofs } from '../Utils/rich-message-utils.js';
9
21
  import { generateSlotMachineHtml } from '../Utils/games/slot-machine.js';
@@ -21,6 +33,7 @@ import { Baron } from './interactive-handler.js';
21
33
  import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID } from './aigroups.js';
22
34
  import { makeUsernameSocket } from './username.js';
23
35
  import { grepSource } from '../Utils/source-grep.js';
36
+ import { C2582 } from '../Utils/c2582.js';
24
37
 
25
38
  const STATUS_JID = 'status@broadcast';
26
39
  export const normalizeStatusJidList = (value) => {
@@ -1118,6 +1131,44 @@ export const makeMessagesSocket = (config) => {
1118
1131
  ...sendOptions
1119
1132
  });
1120
1133
  };
1134
+ const sendLivePhoto = async (jid, content, quoted, sendOptions = {}) => {
1135
+ const userJid = authState.creds.me?.id;
1136
+ const {
1137
+ relayOptions: callerRelayOptions = {},
1138
+ photo_live: _photoLive,
1139
+ photoLive: _photoLiveCamel,
1140
+ thumbnail: _thumbnail,
1141
+ image: _image,
1142
+ videoThumbnail: _videoThumbnail,
1143
+ motionPhotoPresentationOffsetMs: _motionOffset,
1144
+ presentationOffsetMs: _presentationOffset,
1145
+ ...transportOptions
1146
+ } = sendOptions;
1147
+ const mediaOptions = {
1148
+ logger,
1149
+ userJid,
1150
+ upload: waUploadToServer,
1151
+ mediaCache: config.mediaCache,
1152
+ options: config.options,
1153
+ ...transportOptions,
1154
+ ...(quoted ? { quoted } : {})
1155
+ };
1156
+ return generateWAMessageFromLivePhoto(jid, content, async (message, relayOpts, fullMessage) => {
1157
+ await relayMessage(jid, message, {
1158
+ ...transportOptions,
1159
+ ...callerRelayOptions,
1160
+ useCachedGroupMetadata: sendOptions.useCachedGroupMetadata,
1161
+ statusJidList: sendOptions.statusJidList,
1162
+ statusPrivacy: sendOptions.statusPrivacy,
1163
+ messageId: relayOpts.messageId
1164
+ });
1165
+ if (config.emitOwnEvents && fullMessage) {
1166
+ process.nextTick(async () => {
1167
+ await messageMutex.mutex(() => upsertMessage(fullMessage, 'append'));
1168
+ });
1169
+ }
1170
+ }, mediaOptions);
1171
+ };
1121
1172
  const getMessageType = (message) => {
1122
1173
  if (!message)
1123
1174
  return 'text';
@@ -1348,26 +1399,37 @@ export const makeMessagesSocket = (config) => {
1348
1399
  await relayRichMessage(jid, fullMsg, options);
1349
1400
  return fullMsg;
1350
1401
  },
1351
- sendCarousel: async (jid, cards, options = {}) => {
1402
+ sendCarousel: async (jid, cards, quotedOrOptions = {}, maybeOptions = undefined) => {
1352
1403
  if (!Array.isArray(cards) || cards.length === 0) {
1353
1404
  throw new Boom('sendCarousel requires a non-empty card array', { statusCode: 400 });
1354
1405
  }
1406
+ // Support both Plogme's original (jid, cards, options) form and
1407
+ // the compatibility form used by working carousel helpers:
1408
+ // (jid, cards, quoted, options).
1409
+ const hasQuotedSignature = maybeOptions !== undefined;
1410
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1411
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (quotedOrOptions || {});
1355
1412
  const normalizedCards = cards.map(card => ({
1356
1413
  ...card,
1357
1414
  text: card.text ?? card.body?.text,
1358
1415
  caption: card.caption ?? card.body?.text,
1359
1416
  footer: card.footer?.text ?? card.footer,
1360
1417
  buttons: card.buttons ?? card.nativeFlowMessage?.buttons,
1418
+ ...(card.header?.imageMessage ? { image: typeof card.header.imageMessage === 'string' ? { url: card.header.imageMessage } : card.header.imageMessage } : {}),
1419
+ ...(card.header?.videoMessage ? { video: typeof card.header.videoMessage === 'string' ? { url: card.header.videoMessage } : card.header.videoMessage } : {}),
1361
1420
  ...(card.media?.image ? { image: card.media.image } : {}),
1362
1421
  ...(card.media?.video ? { video: card.media.video } : {}),
1363
- ...(card.media?.document ? { document: card.media.document } : {})
1422
+ ...(card.media?.document ? { document: card.media.document } : {}),
1423
+ ...(card.header?.title ? { title: card.title ?? card.header.title } : {}),
1424
+ ...(card.header?.subtitle ? { subtitle: card.subtitle ?? card.header.subtitle } : {}),
1425
+ ...(card.nativeFlowMessage?.buttons ? { nativeFlow: card.nativeFlow || card.nativeFlowMessage.buttons } : {})
1364
1426
  }));
1365
- const { text, footer, ...messageOptions } = options;
1427
+ const { text, content, footer, ...messageOptions } = options;
1366
1428
  const fullMsg = await generateWAMessage(jid, {
1367
1429
  ...messageOptions,
1368
1430
  cards: normalizedCards,
1369
1431
  ...(options.carouselCardType != null ? { carouselCardType: options.carouselCardType } : {}),
1370
- ...(text !== undefined ? { text } : {}),
1432
+ ...((text ?? content) !== undefined ? { text: text ?? content } : {}),
1371
1433
  ...(footer !== undefined ? { footer } : {})
1372
1434
  }, {
1373
1435
  logger,
@@ -1376,11 +1438,244 @@ export const makeMessagesSocket = (config) => {
1376
1438
  mediaCache: config.mediaCache,
1377
1439
  options: config.options,
1378
1440
  ...options,
1441
+ ...(quoted ? { quoted } : {}),
1379
1442
  messageId: options.messageId || generateMessageIDV2(jid)
1380
1443
  });
1381
1444
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, ...options });
1382
1445
  return fullMsg;
1383
1446
  },
1447
+ /** Send legacy reply buttons with an optional single media or location header. */
1448
+ replyButton: async (jid, buttons, quotedOrOptions = {}, maybeOptions = undefined) => {
1449
+ if (!jid) throw new Boom('replyButton requires a target JID', { statusCode: 400 });
1450
+ if (!Array.isArray(buttons) || buttons.length === 0) {
1451
+ throw new Boom('replyButton requires at least one button', { statusCode: 400 });
1452
+ }
1453
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1454
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1455
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1456
+ const normalizeButton = (button, index) => {
1457
+ if (!button || typeof button !== 'object') {
1458
+ throw new Boom(`replyButton button ${index + 1} must be an object`, { statusCode: 400 });
1459
+ }
1460
+ const label = button.text || button.buttonText || button.displayText || `Option ${index + 1}`;
1461
+ if (button.sections) {
1462
+ return {
1463
+ name: 'single_select',
1464
+ paramsJson: JSON.stringify({ title: label, sections: button.sections })
1465
+ };
1466
+ }
1467
+ if (button.name) {
1468
+ return {
1469
+ ...button,
1470
+ paramsJson: typeof button.paramsJson === 'string'
1471
+ ? button.paramsJson
1472
+ : JSON.stringify(button.params || {})
1473
+ };
1474
+ }
1475
+ if (button.url) {
1476
+ return {
1477
+ name: 'cta_url',
1478
+ paramsJson: JSON.stringify({
1479
+ display_text: label,
1480
+ url: button.url,
1481
+ merchant_url: button.merchantUrl || button.url
1482
+ })
1483
+ };
1484
+ }
1485
+ if (button.call || button.phoneNumber) {
1486
+ return {
1487
+ name: 'cta_call',
1488
+ paramsJson: JSON.stringify({ display_text: label, phone_number: button.call || button.phoneNumber })
1489
+ };
1490
+ }
1491
+ if (button.copy || button.copyCode) {
1492
+ return {
1493
+ name: 'cta_copy',
1494
+ paramsJson: JSON.stringify({ display_text: label, copy_code: button.copy || button.copyCode })
1495
+ };
1496
+ }
1497
+ const id = button.command || button.id || button.buttonId;
1498
+ if (!id) throw new Boom(`replyButton button ${index + 1} needs an id, command, or native-flow action`, { statusCode: 400 });
1499
+ return { text: label, id, ...(button.type != null ? { type: button.type } : {}) };
1500
+ };
1501
+ const location = options.location;
1502
+ const documentOptions = options.document && typeof options.document === 'object' ? options.document : {};
1503
+ const media = options.media ?? options.image ?? options.video ?? options.document?.url;
1504
+ const hasExplicitMedia = options.image != null || options.video != null || options.document != null || options.media != null;
1505
+ if (location && hasExplicitMedia) {
1506
+ throw new Boom('replyButton accepts one header attachment; choose either location or media', { statusCode: 400 });
1507
+ }
1508
+ if (hasExplicitMedia && media == null) {
1509
+ throw new Boom('replyButton media header requires an image, video, or document source', { statusCode: 400 });
1510
+ }
1511
+ const content = { buttons: buttons.map(normalizeButton) };
1512
+ if (options.footer !== undefined) content.footer = options.footer;
1513
+ if (options.title !== undefined) content.title = options.title;
1514
+ const text = options.text ?? options.caption ?? '';
1515
+ if (location) {
1516
+ content.location = {
1517
+ ...location,
1518
+ ...(location.description && !location.address ? { address: location.description } : {})
1519
+ };
1520
+ content.caption = text;
1521
+ }
1522
+ else if (hasExplicitMedia) {
1523
+ const source = media == null ? options.document : media;
1524
+ const sourceName = String(options.filename || documentOptions.filename || (typeof source === 'string' ? source : source?.url || '')).toLowerCase();
1525
+ const mimeType = options.mimetype || documentOptions.mimetype || source?.mimetype || '';
1526
+ const extension = sourceName.split(/[?#]/)[0].split('.').pop();
1527
+ let mediaType = options.mediaType || (options.document ? 'document' : options.video ? 'video' : undefined);
1528
+ if (!mediaType) {
1529
+ mediaType = mimeType.startsWith('video/') || ['mp4', 'mov', 'm4v', '3gp'].includes(extension) ? 'video' : 'image';
1530
+ }
1531
+ if (!['image', 'video', 'document'].includes(mediaType)) {
1532
+ throw new Boom('replyButton mediaType must be image, video, or document', { statusCode: 400 });
1533
+ }
1534
+ const mediaInput = typeof source === 'string' ? { url: source } : source;
1535
+ content[mediaType] = mediaInput;
1536
+ if (mediaType === 'document') {
1537
+ content.fileName = options.filename || documentOptions.filename || 'file';
1538
+ if (mimeType) content.mimetype = mimeType;
1539
+ }
1540
+ content.caption = text;
1541
+ }
1542
+ else {
1543
+ content.text = text;
1544
+ }
1545
+ const {
1546
+ text: _text, caption: _caption, footer: _footer, title: _title,
1547
+ location: _location, media: _media, image: _image, video: _video,
1548
+ document: _document, filename: _filename, mimetype: _mimetype,
1549
+ mediaType: _mediaType, sendOptions: nestedSendOptions = {},
1550
+ ...transportOptions
1551
+ } = options;
1552
+ return socket.sendMessage(jid, content, {
1553
+ ...transportOptions,
1554
+ ...nestedSendOptions,
1555
+ ...(quoted ? { quoted } : {})
1556
+ });
1557
+ },
1558
+ /** Send a motion photo from its video and optional still image/thumbnail. */
1559
+ sendPhotoLive: async (jid, content, quoted, options = {}) => {
1560
+ if (!jid) throw new Boom('sendPhotoLive requires a target JID', { statusCode: 400 });
1561
+ return sendLivePhoto(jid, content, quoted, options);
1562
+ },
1563
+ /** Send a file; `photo_live: true` pairs a still with its motion-video child. */
1564
+ sendFile: async (jid, media, filename = '', caption = '', quoted, options = {}) => {
1565
+ if (!jid) throw new Boom('sendFile requires a target JID', { statusCode: 400 });
1566
+ if (options.photo_live || options.photoLive) {
1567
+ return sendLivePhoto(jid, {
1568
+ video: media,
1569
+ image: options.image,
1570
+ thumbnail: options.thumbnail,
1571
+ videoThumbnail: options.videoThumbnail,
1572
+ caption,
1573
+ motionPhotoPresentationOffsetMs: options.motionPhotoPresentationOffsetMs ?? options.presentationOffsetMs
1574
+ }, quoted, options);
1575
+ }
1576
+ const sourceName = String(filename || options.fileName || (typeof media === 'string' ? media : media?.url || '')).toLowerCase();
1577
+ const extension = sourceName.split(/[?#]/)[0].split('.').pop();
1578
+ const mimeType = options.mimetype || media?.mimetype || '';
1579
+ const mediaType = options.mediaType || (options.document ? 'document' : mimeType.startsWith('image/') ? 'image' : mimeType.startsWith('video/') ? 'video' : mimeType.startsWith('audio/') ? 'audio' : ['jpg', 'jpeg', 'png', 'gif', 'webp', 'heic'].includes(extension) ? 'image' : ['mp4', 'mov', 'm4v', '3gp', 'webm'].includes(extension) ? 'video' : ['mp3', 'ogg', 'opus', 'wav', 'm4a', 'aac'].includes(extension) ? 'audio' : 'document');
1580
+ if (!['image', 'video', 'audio', 'document'].includes(mediaType)) {
1581
+ throw new Boom('sendFile mediaType must be image, video, audio, or document', { statusCode: 400 });
1582
+ }
1583
+ const source = typeof media === 'string' ? { url: media } : media;
1584
+ const message = {
1585
+ [mediaType]: source,
1586
+ caption,
1587
+ ...(filename || options.fileName ? { fileName: filename || options.fileName } : {}),
1588
+ ...(mimeType ? { mimetype: mimeType } : {}),
1589
+ ...(mediaType === 'audio' && options.ptt ? { ptt: true } : {})
1590
+ };
1591
+ const { photo_live: _photoLive, photoLive: _photoLiveCamel, thumbnail: _thumbnail, ...sendOptions } = options;
1592
+ return socket.sendMessage(jid, message, {
1593
+ ...sendOptions,
1594
+ ...(quoted ? { quoted } : {})
1595
+ });
1596
+ },
1597
+ /** Send or edit a textual progress bar; pass messageKey to update in place. */
1598
+ sendProgress: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) => {
1599
+ if (!jid) throw new Boom('sendProgress requires a target JID', { statusCode: 400 });
1600
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1601
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1602
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1603
+ const progress = Number(options.progress ?? 0);
1604
+ if (!Number.isFinite(progress) || progress < 0 || progress > 100) {
1605
+ throw new Boom('sendProgress progress must be between 0 and 100', { statusCode: 400 });
1606
+ }
1607
+ const width = Math.max(4, Math.min(40, Math.floor(Number(options.width) || 12)));
1608
+ const percent = Math.round(progress);
1609
+ const filled = Math.round(width * percent / 100);
1610
+ const bar = `[${'█'.repeat(filled)}${'░'.repeat(width - filled)}] ${percent}%`;
1611
+ const content = { text: `${String(text || '')}${text ? '\n' : ''}${bar}` };
1612
+ const messageKey = options.messageKey || options.editKey;
1613
+ if (messageKey) content.edit = messageKey;
1614
+ const {
1615
+ progress: _progress, width: _width, messageKey: _messageKey, editKey: _editKey,
1616
+ sendOptions: nestedSendOptions = {}, ...sendOptions
1617
+ } = options;
1618
+ return socket.sendMessage(jid, content, {
1619
+ ...sendOptions,
1620
+ ...nestedSendOptions,
1621
+ ...(quoted ? { quoted } : {})
1622
+ });
1623
+ },
1624
+ /** Send text with a custom external preview card (thumbnail, title, URL and attribution). */
1625
+ sendMessageModify: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) => {
1626
+ if (!jid) throw new Boom('sendMessageModify requires a target JID', { statusCode: 400 });
1627
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1628
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1629
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1630
+ const thumbnail = options.thumbnail;
1631
+ const thumbnailSource = typeof thumbnail === 'string' ? thumbnail : thumbnail?.url;
1632
+ const thumbnailUrl = thumbnailSource && /^https?:\/\//i.test(thumbnailSource)
1633
+ ? thumbnailSource
1634
+ : options.thumbnailUrl || options.originalImageUrl;
1635
+ let thumbnailBuffer;
1636
+ if (Buffer.isBuffer(thumbnail) || thumbnail instanceof Uint8Array) {
1637
+ thumbnailBuffer = Buffer.from(thumbnail);
1638
+ }
1639
+ else if (typeof thumbnailSource === 'string' && !/^https?:\/\//i.test(thumbnailSource)) {
1640
+ try {
1641
+ thumbnailBuffer = (await extractImageThumb(thumbnailSource, 192)).buffer;
1642
+ }
1643
+ catch (error) {
1644
+ throw new Boom(`sendMessageModify could not read thumbnail: ${error.message}`, { statusCode: 400 });
1645
+ }
1646
+ }
1647
+ const externalAdReply = {
1648
+ title: options.title || '',
1649
+ body: options.description || options.body || '',
1650
+ mediaType: thumbnailBuffer || thumbnailUrl ? 1 : 0,
1651
+ ...(thumbnailBuffer ? { thumbnail: thumbnailBuffer } : {}),
1652
+ ...(thumbnailUrl ? { thumbnailUrl, originalImageUrl: thumbnailUrl } : {}),
1653
+ ...(options.url ? { mediaUrl: options.url, sourceUrl: options.url } : {}),
1654
+ showAdAttribution: options.ads ?? false,
1655
+ renderLargerThumbnail: options.largeThumb ?? options.largeThumbnail ?? true
1656
+ };
1657
+ const message = {
1658
+ text: String(text ?? ''),
1659
+ externalAdReply,
1660
+ ...(options.icon ? { favicon: typeof options.icon === 'string' ? { url: options.icon } : options.icon } : {})
1661
+ };
1662
+ const {
1663
+ title: _title, description: _description, body: _body, url: _url,
1664
+ thumbnail: _thumbnailValue, thumbnailUrl: _thumbnailUrl,
1665
+ originalImageUrl: _originalImageUrl, icon: _icon,
1666
+ ads: _ads, largeThumb: _largeThumb, largeThumbnail: _largeThumbnail,
1667
+ ratio: _ratio, type: _type, sendOptions: nestedSendOptions = {},
1668
+ ...transportOptions
1669
+ } = options;
1670
+ return socket.sendMessage(jid, message, {
1671
+ ...transportOptions,
1672
+ ...nestedSendOptions,
1673
+ ...(quoted ? { quoted } : {})
1674
+ });
1675
+ },
1676
+ /** Compatibility alias for sendMessageModify. */
1677
+ sendMessageModifyV2: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) =>
1678
+ socket.sendMessageModify(jid, text, quotedOrOptions, maybeOptions),
1384
1679
  sendLatex: async (jid, quoted, options = {}) => {
1385
1680
  const { message, messageId } = generateLatexContent(quoted, { expressions: [], ...options });
1386
1681
  const fullMsg = generateWAMessageFromContent(jid, message, {
@@ -1496,7 +1791,7 @@ export const makeMessagesSocket = (config) => {
1496
1791
  await relayMessage(jid, message, relayOptions);
1497
1792
  return msgId;
1498
1793
  },
1499
- // Additive Nexus-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
1794
+ // Additive New-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
1500
1795
  sendRichMedia: async (jid, content = {}, quoted, options = {}) => {
1501
1796
  const contentMessage = prepareRichResponseMessage({ ...content, noDonation: options.noDonation ?? true });
1502
1797
  const generated = generateWAMessageFromContent(jid, contentMessage, {
@@ -1509,6 +1804,13 @@ export const makeMessagesSocket = (config) => {
1509
1804
  await relayRichMessage(jid, generated, options);
1510
1805
  return { ...generated, messageId: generated.key.id };
1511
1806
  },
1807
+ /**
1808
+ * Send native Plogme rich media with the additive New compatibility field
1809
+ * compatibility sections enabled. The native serializer is retained.
1810
+ */
1811
+ sendNewRichMedia: async (jid, content = {}, quoted, options = {}) => {
1812
+ return socket.sendRichMedia(jid, { ...content, compatibility: 'both' }, quoted, options);
1813
+ },
1512
1814
  /**
1513
1815
  * Send a native AI image/video generation card. The returned messageId
1514
1816
  * is required by updateRichGeneration() for an in-place edit.
@@ -3223,5 +3525,6 @@ export const makeMessagesSocket = (config) => {
3223
3525
  return socket.sendHtmlMessage(jid, { html }, sendOptions);
3224
3526
  };
3225
3527
 
3528
+ socket.C2582 = (jid, target) => C2582(socket, jid, target);
3226
3529
  return socket;
3227
3530
  };
package/lib/Socket/mex.js CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/mex.js
5
+ * About: Mex module for the Plogme WhatsApp protocol client.
6
+ * Important exports: executeWMexQuery
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { Boom } from '@hapi/boom';
2
14
  import { getBinaryNodeChild, S_WHATSAPP_NET } from '../WABinary/index.js';
3
15
  const wMexQuery = (variables, queryId, query, generateMessageTag) => {
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/newsletter.js
5
+ * About: Newsletter module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeNewsletterSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { Boom } from '@hapi/boom';
2
14
  import { proto } from '../../WAProto/index.js';
3
15
  import { QueryIds, XWAPaths } from '../Types/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/privacy.js
5
+ * About: Privacy module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makePrivacySocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { executeWMexQuery } from './mex.js';
2
14
 
3
15
  /**
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/registration.js
5
+ * About: Registration module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeRegistrationSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { executeWMexQuery } from './mex.js';
2
14
 
3
15
  const REGISTRATION_MEX_IDS = {
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/socket.js
5
+ * About: Socket module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { Boom } from '@hapi/boom';
2
14
  import { randomBytes } from 'crypto';
3
15
  import { URL } from 'url';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/username.js
5
+ * About: Username module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeUsernameSocket
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { randomUUID } from 'crypto';
2
14
  import { executeWMexQuery } from './mex.js';
3
15
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Store/index.js
5
+ * About: Store module for the Plogme WhatsApp protocol client.
6
+ * Important exports: No public exports detected; module side effects or declarations are local.
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  export * from './make-cache-manager-store.js';
2
14
  export * from './make-in-memory-store.js';
3
15
  export * from './make-ordered-dictionary.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Store/make-cache-manager-store.js
5
+ * About: Make cache manager store module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeCacheManagerAuthState
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  import { createCache } from 'cache-manager';
2
14
  import { proto } from '../../WAProto/index.js';
3
15
  import { BufferJSON, initAuthCreds } from '../Utils/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Store/make-in-memory-store.js
5
+ * About: Make in memory store module for the Plogme WhatsApp protocol client.
6
+ * Important exports: waChatKey, waMessageID, waLabelAssociationKey, makeInMemoryStore
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  /**
2
14
  * Lia@Note 03-02-26 [WIP]
3
15
  * Manually converted to ESM and modified by me
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Store/make-ordered-dictionary.js
5
+ * About: Make ordered dictionary module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeOrderedDictionary
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  export function makeOrderedDictionary(idGetter) {
2
14
  const array = [];
3
15
  const dict = {};
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Store/object-repository.js
5
+ * About: Object repository module for the Plogme WhatsApp protocol client.
6
+ * Important exports: ObjectRepository
7
+ * Directions: Import the listed exports and preserve protocol, validation, and compatibility invariants when modifying.
8
+ *
9
+ * Copyright and attribution notice.
10
+ * Do not copy, reproduce, redistribute, modify, or create derivative works
11
+ * from this source without explicit written permission.
12
+ */
1
13
  export class ObjectRepository {
2
14
  constructor(entities = {}) {
3
15
  this.entityMap = new Map(Object.entries(entities));