plogme 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +226 -2
  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 +358 -7
  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/channel-policy.js +12 -0
  73. package/lib/Utils/chat-utils.js +12 -0
  74. package/lib/Utils/companion-reg-client-utils.js +12 -0
  75. package/lib/Utils/consumer-application.js +12 -0
  76. package/lib/Utils/crypto.js +12 -0
  77. package/lib/Utils/decode-wa-message.js +12 -0
  78. package/lib/Utils/event-buffer.js +12 -0
  79. package/lib/Utils/games/miniapp.js +12 -0
  80. package/lib/Utils/games/slot-machine.js +12 -0
  81. package/lib/Utils/games/website-preview.js +12 -0
  82. package/lib/Utils/generics.js +12 -0
  83. package/lib/Utils/group-history.js +12 -0
  84. package/lib/Utils/history.js +12 -0
  85. package/lib/Utils/identity-change-handler.js +12 -0
  86. package/lib/Utils/index.js +12 -0
  87. package/lib/Utils/jid-display-normalization.js +12 -0
  88. package/lib/Utils/link-preview.js +12 -0
  89. package/lib/Utils/logger.js +12 -0
  90. package/lib/Utils/lt-hash.js +12 -0
  91. package/lib/Utils/make-mutex.js +12 -0
  92. package/lib/Utils/message-composer.js +18 -1
  93. package/lib/Utils/message-inspect.js +12 -0
  94. package/lib/Utils/message-retry-manager.js +12 -0
  95. package/lib/Utils/messages-media.js +12 -0
  96. package/lib/Utils/messages.js +232 -4
  97. package/lib/Utils/meta-ai-msmsg.js +12 -0
  98. package/lib/Utils/meta-compositing.js +12 -0
  99. package/lib/Utils/native-flow.js +12 -0
  100. package/lib/Utils/noise-handler.js +12 -0
  101. package/lib/Utils/offline-node-processor.js +12 -0
  102. package/lib/Utils/pre-key-manager.js +12 -0
  103. package/lib/Utils/process-message.js +12 -0
  104. package/lib/Utils/reporting-utils.js +12 -0
  105. package/lib/Utils/rich-message-utils.js +484 -91
  106. package/lib/Utils/signal.js +12 -0
  107. package/lib/Utils/source-grep.js +12 -0
  108. package/lib/Utils/stanza-ack.js +12 -0
  109. package/lib/Utils/sync-action-utils.js +12 -0
  110. package/lib/Utils/tc-token-utils.js +12 -0
  111. package/lib/Utils/use-multi-file-auth-state.js +12 -0
  112. package/lib/Utils/use-single-file-auth-state.js +12 -0
  113. package/lib/Utils/use-sqlite-auth-state.js +12 -0
  114. package/lib/Utils/validate-connection.js +12 -0
  115. package/lib/Utils/view-once-utils.js +12 -0
  116. package/lib/Utils/voip-rekey.js +12 -0
  117. package/lib/Utils/welcome-flow.js +12 -0
  118. package/lib/WABinary/constants.js +12 -0
  119. package/lib/WABinary/decode.js +12 -0
  120. package/lib/WABinary/encode.js +12 -0
  121. package/lib/WABinary/generic-utils.js +12 -0
  122. package/lib/WABinary/index.js +12 -0
  123. package/lib/WABinary/jid-utils.js +12 -0
  124. package/lib/WABinary/types.js +12 -0
  125. package/lib/WAM/BinaryInfo.js +12 -0
  126. package/lib/WAM/constants.js +12 -0
  127. package/lib/WAM/encode.js +12 -0
  128. package/lib/WAM/index.js +12 -0
  129. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +12 -0
  130. package/lib/WAUSync/Protocols/USyncContactProtocol.js +12 -0
  131. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +12 -0
  132. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +12 -0
  133. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +12 -0
  134. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +12 -0
  135. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +12 -0
  136. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +12 -0
  137. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +12 -0
  138. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +12 -0
  139. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +12 -0
  140. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +12 -0
  141. package/lib/WAUSync/Protocols/index.js +12 -0
  142. package/lib/WAUSync/USyncQuery.js +12 -0
  143. package/lib/WAUSync/USyncUser.js +12 -0
  144. package/lib/WAUSync/index.js +12 -0
  145. package/lib/index.d.ts +50 -2
  146. package/lib/index.js +12 -0
  147. package/package.json +9 -2
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/aigroups.js
5
+ * About: Aigroups module for the Plogme WhatsApp protocol client.
6
+ * Important exports: META_AI_BOT_JID, isMetaAIBotResponse, collectMetaAIBotParticipantJids, makeAIGroupsSocket, extractAIGroupMetadata
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 { WAMessageAddressingMode } from '../Types/index.js';
2
14
  import { generateMessageIDV2, normalizeMessageContent } from '../Utils/index.js';
3
15
  import { getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidEncode, jidNormalizedUser } from '../WABinary/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/ban-checker.js
5
+ * About: Ban checker module for the Plogme WhatsApp protocol client.
6
+ * Important exports: checkStatusWA, getBanDetails, normalizePhone
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, randomUUID } from 'crypto';
2
14
  import { initAuthCreds } from '../Utils/auth-utils.js';
3
15
  import { Curve, md5, signedKeyPair } from '../Utils/crypto.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/business.js
5
+ * About: Business module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeBusinessSocket
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 { unlink } from 'node:fs/promises';
2
14
  import { getRawMediaUploadData } from '../Utils/index.js';
3
15
  import { parseCatalogNode, parseCollectionsNode, parseOrderDetailsNode, parseProductNode, toProductNode, uploadingNecessaryImagesOfProduct } from '../Utils/business.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/chats.js
5
+ * About: Chats module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeChatsSocket
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 { proto } from '../../WAProto/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/communities.js
5
+ * About: Communities module for the Plogme WhatsApp protocol client.
6
+ * Important exports: makeCommunitiesSocket, extractCommunityMetadata
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 { proto } from '../../WAProto/index.js';
2
14
  import { WAMessageStubType } from '../Types/index.js';
3
15
  import { generateMessageID, generateMessageIDV2, unixTimestampSeconds } from '../Utils/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/graphql.js
5
+ * About: Graphql module for the Plogme WhatsApp protocol client.
6
+ * Important exports: executeWWWGraphQL, executeFacebookGraphQL, executeWamoGraphQL, makeGraphQLSocket
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
 
3
15
  // Endpoints confirmed from APX.java and WamoGraphQLExecutor.java
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/groups.js
5
+ * About: Groups module for the Plogme WhatsApp protocol client.
6
+ * Important exports: buildReportNode, buildGroupStatusRevokeMessage, makeGroupsSocket, extractGroupMetadata
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 { WAMessageAddressingMode, WAMessageStubType } from '../Types/index.js';
@@ -1,3 +1,15 @@
1
+ /**
2
+ * @crysnpvax
3
+ *
4
+ * File: lib/Socket/index.js
5
+ * About: Socket module for the Plogme WhatsApp protocol client.
6
+ * Important exports: checkStatusWA
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 { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
2
14
  import { makeCommunitiesSocket } from './communities.js';
3
15
  import { makeInteropSocket } from './interop.js';
@@ -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, 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';
@@ -1093,6 +1105,69 @@ export const makeMessagesSocket = (config) => {
1093
1105
  return fullMsg;
1094
1106
  };
1095
1107
 
1108
+ const sendImagePoll = async (jid, poll, sendOptions = {}) => {
1109
+ const userJid = authState.creds.me.id;
1110
+ const { additionalNodes: _callerNodes, ...relayBaseOptions } = sendOptions;
1111
+ return generateWAMessageFromImagePoll(jid, poll, async (message, relayOptions, fullMessage) => {
1112
+ await relayMessage(jid, message, {
1113
+ ...relayBaseOptions,
1114
+ useCachedGroupMetadata: sendOptions.useCachedGroupMetadata,
1115
+ statusJidList: sendOptions.statusJidList,
1116
+ statusPrivacy: sendOptions.statusPrivacy,
1117
+ ...relayOptions
1118
+ });
1119
+ if (config.emitOwnEvents && fullMessage) {
1120
+ process.nextTick(async () => {
1121
+ await messageMutex.mutex(() => upsertMessage(fullMessage, 'append'));
1122
+ });
1123
+ }
1124
+ }, {
1125
+ logger,
1126
+ userJid,
1127
+ upload: waUploadToServer,
1128
+ mediaCache: config.mediaCache,
1129
+ options: config.options,
1130
+ ...sendOptions
1131
+ });
1132
+ };
1133
+ const sendLivePhoto = async (jid, content, quoted, sendOptions = {}) => {
1134
+ const userJid = authState.creds.me?.id;
1135
+ const {
1136
+ relayOptions: callerRelayOptions = {},
1137
+ photo_live: _photoLive,
1138
+ photoLive: _photoLiveCamel,
1139
+ thumbnail: _thumbnail,
1140
+ image: _image,
1141
+ videoThumbnail: _videoThumbnail,
1142
+ motionPhotoPresentationOffsetMs: _motionOffset,
1143
+ presentationOffsetMs: _presentationOffset,
1144
+ ...transportOptions
1145
+ } = sendOptions;
1146
+ const mediaOptions = {
1147
+ logger,
1148
+ userJid,
1149
+ upload: waUploadToServer,
1150
+ mediaCache: config.mediaCache,
1151
+ options: config.options,
1152
+ ...transportOptions,
1153
+ ...(quoted ? { quoted } : {})
1154
+ };
1155
+ return generateWAMessageFromLivePhoto(jid, content, async (message, relayOpts, fullMessage) => {
1156
+ await relayMessage(jid, message, {
1157
+ ...transportOptions,
1158
+ ...callerRelayOptions,
1159
+ useCachedGroupMetadata: sendOptions.useCachedGroupMetadata,
1160
+ statusJidList: sendOptions.statusJidList,
1161
+ statusPrivacy: sendOptions.statusPrivacy,
1162
+ messageId: relayOpts.messageId
1163
+ });
1164
+ if (config.emitOwnEvents && fullMessage) {
1165
+ process.nextTick(async () => {
1166
+ await messageMutex.mutex(() => upsertMessage(fullMessage, 'append'));
1167
+ });
1168
+ }
1169
+ }, mediaOptions);
1170
+ };
1096
1171
  const getMessageType = (message) => {
1097
1172
  if (!message)
1098
1173
  return 'text';
@@ -1323,26 +1398,37 @@ export const makeMessagesSocket = (config) => {
1323
1398
  await relayRichMessage(jid, fullMsg, options);
1324
1399
  return fullMsg;
1325
1400
  },
1326
- sendCarousel: async (jid, cards, options = {}) => {
1401
+ sendCarousel: async (jid, cards, quotedOrOptions = {}, maybeOptions = undefined) => {
1327
1402
  if (!Array.isArray(cards) || cards.length === 0) {
1328
1403
  throw new Boom('sendCarousel requires a non-empty card array', { statusCode: 400 });
1329
1404
  }
1405
+ // Support both Plogme's original (jid, cards, options) form and
1406
+ // the compatibility form used by working carousel helpers:
1407
+ // (jid, cards, quoted, options).
1408
+ const hasQuotedSignature = maybeOptions !== undefined;
1409
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1410
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (quotedOrOptions || {});
1330
1411
  const normalizedCards = cards.map(card => ({
1331
1412
  ...card,
1332
1413
  text: card.text ?? card.body?.text,
1333
1414
  caption: card.caption ?? card.body?.text,
1334
1415
  footer: card.footer?.text ?? card.footer,
1335
1416
  buttons: card.buttons ?? card.nativeFlowMessage?.buttons,
1417
+ ...(card.header?.imageMessage ? { image: typeof card.header.imageMessage === 'string' ? { url: card.header.imageMessage } : card.header.imageMessage } : {}),
1418
+ ...(card.header?.videoMessage ? { video: typeof card.header.videoMessage === 'string' ? { url: card.header.videoMessage } : card.header.videoMessage } : {}),
1336
1419
  ...(card.media?.image ? { image: card.media.image } : {}),
1337
1420
  ...(card.media?.video ? { video: card.media.video } : {}),
1338
- ...(card.media?.document ? { document: card.media.document } : {})
1421
+ ...(card.media?.document ? { document: card.media.document } : {}),
1422
+ ...(card.header?.title ? { title: card.title ?? card.header.title } : {}),
1423
+ ...(card.header?.subtitle ? { subtitle: card.subtitle ?? card.header.subtitle } : {}),
1424
+ ...(card.nativeFlowMessage?.buttons ? { nativeFlow: card.nativeFlow || card.nativeFlowMessage.buttons } : {})
1339
1425
  }));
1340
- const { text, footer, ...messageOptions } = options;
1426
+ const { text, content, footer, ...messageOptions } = options;
1341
1427
  const fullMsg = await generateWAMessage(jid, {
1342
1428
  ...messageOptions,
1343
1429
  cards: normalizedCards,
1344
1430
  ...(options.carouselCardType != null ? { carouselCardType: options.carouselCardType } : {}),
1345
- ...(text !== undefined ? { text } : {}),
1431
+ ...((text ?? content) !== undefined ? { text: text ?? content } : {}),
1346
1432
  ...(footer !== undefined ? { footer } : {})
1347
1433
  }, {
1348
1434
  logger,
@@ -1351,11 +1437,244 @@ export const makeMessagesSocket = (config) => {
1351
1437
  mediaCache: config.mediaCache,
1352
1438
  options: config.options,
1353
1439
  ...options,
1440
+ ...(quoted ? { quoted } : {}),
1354
1441
  messageId: options.messageId || generateMessageIDV2(jid)
1355
1442
  });
1356
1443
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, ...options });
1357
1444
  return fullMsg;
1358
1445
  },
1446
+ /** Send legacy reply buttons with an optional single media or location header. */
1447
+ replyButton: async (jid, buttons, quotedOrOptions = {}, maybeOptions = undefined) => {
1448
+ if (!jid) throw new Boom('replyButton requires a target JID', { statusCode: 400 });
1449
+ if (!Array.isArray(buttons) || buttons.length === 0) {
1450
+ throw new Boom('replyButton requires at least one button', { statusCode: 400 });
1451
+ }
1452
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1453
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1454
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1455
+ const normalizeButton = (button, index) => {
1456
+ if (!button || typeof button !== 'object') {
1457
+ throw new Boom(`replyButton button ${index + 1} must be an object`, { statusCode: 400 });
1458
+ }
1459
+ const label = button.text || button.buttonText || button.displayText || `Option ${index + 1}`;
1460
+ if (button.sections) {
1461
+ return {
1462
+ name: 'single_select',
1463
+ paramsJson: JSON.stringify({ title: label, sections: button.sections })
1464
+ };
1465
+ }
1466
+ if (button.name) {
1467
+ return {
1468
+ ...button,
1469
+ paramsJson: typeof button.paramsJson === 'string'
1470
+ ? button.paramsJson
1471
+ : JSON.stringify(button.params || {})
1472
+ };
1473
+ }
1474
+ if (button.url) {
1475
+ return {
1476
+ name: 'cta_url',
1477
+ paramsJson: JSON.stringify({
1478
+ display_text: label,
1479
+ url: button.url,
1480
+ merchant_url: button.merchantUrl || button.url
1481
+ })
1482
+ };
1483
+ }
1484
+ if (button.call || button.phoneNumber) {
1485
+ return {
1486
+ name: 'cta_call',
1487
+ paramsJson: JSON.stringify({ display_text: label, phone_number: button.call || button.phoneNumber })
1488
+ };
1489
+ }
1490
+ if (button.copy || button.copyCode) {
1491
+ return {
1492
+ name: 'cta_copy',
1493
+ paramsJson: JSON.stringify({ display_text: label, copy_code: button.copy || button.copyCode })
1494
+ };
1495
+ }
1496
+ const id = button.command || button.id || button.buttonId;
1497
+ if (!id) throw new Boom(`replyButton button ${index + 1} needs an id, command, or native-flow action`, { statusCode: 400 });
1498
+ return { text: label, id, ...(button.type != null ? { type: button.type } : {}) };
1499
+ };
1500
+ const location = options.location;
1501
+ const documentOptions = options.document && typeof options.document === 'object' ? options.document : {};
1502
+ const media = options.media ?? options.image ?? options.video ?? options.document?.url;
1503
+ const hasExplicitMedia = options.image != null || options.video != null || options.document != null || options.media != null;
1504
+ if (location && hasExplicitMedia) {
1505
+ throw new Boom('replyButton accepts one header attachment; choose either location or media', { statusCode: 400 });
1506
+ }
1507
+ if (hasExplicitMedia && media == null) {
1508
+ throw new Boom('replyButton media header requires an image, video, or document source', { statusCode: 400 });
1509
+ }
1510
+ const content = { buttons: buttons.map(normalizeButton) };
1511
+ if (options.footer !== undefined) content.footer = options.footer;
1512
+ if (options.title !== undefined) content.title = options.title;
1513
+ const text = options.text ?? options.caption ?? '';
1514
+ if (location) {
1515
+ content.location = {
1516
+ ...location,
1517
+ ...(location.description && !location.address ? { address: location.description } : {})
1518
+ };
1519
+ content.caption = text;
1520
+ }
1521
+ else if (hasExplicitMedia) {
1522
+ const source = media == null ? options.document : media;
1523
+ const sourceName = String(options.filename || documentOptions.filename || (typeof source === 'string' ? source : source?.url || '')).toLowerCase();
1524
+ const mimeType = options.mimetype || documentOptions.mimetype || source?.mimetype || '';
1525
+ const extension = sourceName.split(/[?#]/)[0].split('.').pop();
1526
+ let mediaType = options.mediaType || (options.document ? 'document' : options.video ? 'video' : undefined);
1527
+ if (!mediaType) {
1528
+ mediaType = mimeType.startsWith('video/') || ['mp4', 'mov', 'm4v', '3gp'].includes(extension) ? 'video' : 'image';
1529
+ }
1530
+ if (!['image', 'video', 'document'].includes(mediaType)) {
1531
+ throw new Boom('replyButton mediaType must be image, video, or document', { statusCode: 400 });
1532
+ }
1533
+ const mediaInput = typeof source === 'string' ? { url: source } : source;
1534
+ content[mediaType] = mediaInput;
1535
+ if (mediaType === 'document') {
1536
+ content.fileName = options.filename || documentOptions.filename || 'file';
1537
+ if (mimeType) content.mimetype = mimeType;
1538
+ }
1539
+ content.caption = text;
1540
+ }
1541
+ else {
1542
+ content.text = text;
1543
+ }
1544
+ const {
1545
+ text: _text, caption: _caption, footer: _footer, title: _title,
1546
+ location: _location, media: _media, image: _image, video: _video,
1547
+ document: _document, filename: _filename, mimetype: _mimetype,
1548
+ mediaType: _mediaType, sendOptions: nestedSendOptions = {},
1549
+ ...transportOptions
1550
+ } = options;
1551
+ return socket.sendMessage(jid, content, {
1552
+ ...transportOptions,
1553
+ ...nestedSendOptions,
1554
+ ...(quoted ? { quoted } : {})
1555
+ });
1556
+ },
1557
+ /** Send a motion photo from its video and optional still image/thumbnail. */
1558
+ sendPhotoLive: async (jid, content, quoted, options = {}) => {
1559
+ if (!jid) throw new Boom('sendPhotoLive requires a target JID', { statusCode: 400 });
1560
+ return sendLivePhoto(jid, content, quoted, options);
1561
+ },
1562
+ /** Send a file; `photo_live: true` pairs a still with its motion-video child. */
1563
+ sendFile: async (jid, media, filename = '', caption = '', quoted, options = {}) => {
1564
+ if (!jid) throw new Boom('sendFile requires a target JID', { statusCode: 400 });
1565
+ if (options.photo_live || options.photoLive) {
1566
+ return sendLivePhoto(jid, {
1567
+ video: media,
1568
+ image: options.image,
1569
+ thumbnail: options.thumbnail,
1570
+ videoThumbnail: options.videoThumbnail,
1571
+ caption,
1572
+ motionPhotoPresentationOffsetMs: options.motionPhotoPresentationOffsetMs ?? options.presentationOffsetMs
1573
+ }, quoted, options);
1574
+ }
1575
+ const sourceName = String(filename || options.fileName || (typeof media === 'string' ? media : media?.url || '')).toLowerCase();
1576
+ const extension = sourceName.split(/[?#]/)[0].split('.').pop();
1577
+ const mimeType = options.mimetype || media?.mimetype || '';
1578
+ 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');
1579
+ if (!['image', 'video', 'audio', 'document'].includes(mediaType)) {
1580
+ throw new Boom('sendFile mediaType must be image, video, audio, or document', { statusCode: 400 });
1581
+ }
1582
+ const source = typeof media === 'string' ? { url: media } : media;
1583
+ const message = {
1584
+ [mediaType]: source,
1585
+ caption,
1586
+ ...(filename || options.fileName ? { fileName: filename || options.fileName } : {}),
1587
+ ...(mimeType ? { mimetype: mimeType } : {}),
1588
+ ...(mediaType === 'audio' && options.ptt ? { ptt: true } : {})
1589
+ };
1590
+ const { photo_live: _photoLive, photoLive: _photoLiveCamel, thumbnail: _thumbnail, ...sendOptions } = options;
1591
+ return socket.sendMessage(jid, message, {
1592
+ ...sendOptions,
1593
+ ...(quoted ? { quoted } : {})
1594
+ });
1595
+ },
1596
+ /** Send or edit a textual progress bar; pass messageKey to update in place. */
1597
+ sendProgress: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) => {
1598
+ if (!jid) throw new Boom('sendProgress requires a target JID', { statusCode: 400 });
1599
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1600
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1601
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1602
+ const progress = Number(options.progress ?? 0);
1603
+ if (!Number.isFinite(progress) || progress < 0 || progress > 100) {
1604
+ throw new Boom('sendProgress progress must be between 0 and 100', { statusCode: 400 });
1605
+ }
1606
+ const width = Math.max(4, Math.min(40, Math.floor(Number(options.width) || 12)));
1607
+ const percent = Math.round(progress);
1608
+ const filled = Math.round(width * percent / 100);
1609
+ const bar = `[${'█'.repeat(filled)}${'░'.repeat(width - filled)}] ${percent}%`;
1610
+ const content = { text: `${String(text || '')}${text ? '\n' : ''}${bar}` };
1611
+ const messageKey = options.messageKey || options.editKey;
1612
+ if (messageKey) content.edit = messageKey;
1613
+ const {
1614
+ progress: _progress, width: _width, messageKey: _messageKey, editKey: _editKey,
1615
+ sendOptions: nestedSendOptions = {}, ...sendOptions
1616
+ } = options;
1617
+ return socket.sendMessage(jid, content, {
1618
+ ...sendOptions,
1619
+ ...nestedSendOptions,
1620
+ ...(quoted ? { quoted } : {})
1621
+ });
1622
+ },
1623
+ /** Send text with a custom external preview card (thumbnail, title, URL and attribution). */
1624
+ sendMessageModify: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) => {
1625
+ if (!jid) throw new Boom('sendMessageModify requires a target JID', { statusCode: 400 });
1626
+ const hasQuotedSignature = !!(quotedOrOptions?.key && quotedOrOptions?.message);
1627
+ const quoted = hasQuotedSignature ? quotedOrOptions : undefined;
1628
+ const options = hasQuotedSignature ? (maybeOptions || {}) : (maybeOptions || quotedOrOptions || {});
1629
+ const thumbnail = options.thumbnail;
1630
+ const thumbnailSource = typeof thumbnail === 'string' ? thumbnail : thumbnail?.url;
1631
+ const thumbnailUrl = thumbnailSource && /^https?:\/\//i.test(thumbnailSource)
1632
+ ? thumbnailSource
1633
+ : options.thumbnailUrl || options.originalImageUrl;
1634
+ let thumbnailBuffer;
1635
+ if (Buffer.isBuffer(thumbnail) || thumbnail instanceof Uint8Array) {
1636
+ thumbnailBuffer = Buffer.from(thumbnail);
1637
+ }
1638
+ else if (typeof thumbnailSource === 'string' && !/^https?:\/\//i.test(thumbnailSource)) {
1639
+ try {
1640
+ thumbnailBuffer = (await extractImageThumb(thumbnailSource, 192)).buffer;
1641
+ }
1642
+ catch (error) {
1643
+ throw new Boom(`sendMessageModify could not read thumbnail: ${error.message}`, { statusCode: 400 });
1644
+ }
1645
+ }
1646
+ const externalAdReply = {
1647
+ title: options.title || '',
1648
+ body: options.description || options.body || '',
1649
+ mediaType: thumbnailBuffer || thumbnailUrl ? 1 : 0,
1650
+ ...(thumbnailBuffer ? { thumbnail: thumbnailBuffer } : {}),
1651
+ ...(thumbnailUrl ? { thumbnailUrl, originalImageUrl: thumbnailUrl } : {}),
1652
+ ...(options.url ? { mediaUrl: options.url, sourceUrl: options.url } : {}),
1653
+ showAdAttribution: options.ads ?? false,
1654
+ renderLargerThumbnail: options.largeThumb ?? options.largeThumbnail ?? true
1655
+ };
1656
+ const message = {
1657
+ text: String(text ?? ''),
1658
+ externalAdReply,
1659
+ ...(options.icon ? { favicon: typeof options.icon === 'string' ? { url: options.icon } : options.icon } : {})
1660
+ };
1661
+ const {
1662
+ title: _title, description: _description, body: _body, url: _url,
1663
+ thumbnail: _thumbnailValue, thumbnailUrl: _thumbnailUrl,
1664
+ originalImageUrl: _originalImageUrl, icon: _icon,
1665
+ ads: _ads, largeThumb: _largeThumb, largeThumbnail: _largeThumbnail,
1666
+ ratio: _ratio, type: _type, sendOptions: nestedSendOptions = {},
1667
+ ...transportOptions
1668
+ } = options;
1669
+ return socket.sendMessage(jid, message, {
1670
+ ...transportOptions,
1671
+ ...nestedSendOptions,
1672
+ ...(quoted ? { quoted } : {})
1673
+ });
1674
+ },
1675
+ /** Compatibility alias for sendMessageModify. */
1676
+ sendMessageModifyV2: async (jid, text, quotedOrOptions = {}, maybeOptions = undefined) =>
1677
+ socket.sendMessageModify(jid, text, quotedOrOptions, maybeOptions),
1359
1678
  sendLatex: async (jid, quoted, options = {}) => {
1360
1679
  const { message, messageId } = generateLatexContent(quoted, { expressions: [], ...options });
1361
1680
  const fullMsg = generateWAMessageFromContent(jid, message, {
@@ -1471,7 +1790,7 @@ export const makeMessagesSocket = (config) => {
1471
1790
  await relayMessage(jid, message, relayOptions);
1472
1791
  return msgId;
1473
1792
  },
1474
- // Additive Nexus-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
1793
+ // Additive New-compatible AI-rich helpers. Existing Gen4/table/grid/carousel APIs remain unchanged.
1475
1794
  sendRichMedia: async (jid, content = {}, quoted, options = {}) => {
1476
1795
  const contentMessage = prepareRichResponseMessage({ ...content, noDonation: options.noDonation ?? true });
1477
1796
  const generated = generateWAMessageFromContent(jid, contentMessage, {
@@ -1484,6 +1803,13 @@ export const makeMessagesSocket = (config) => {
1484
1803
  await relayRichMessage(jid, generated, options);
1485
1804
  return { ...generated, messageId: generated.key.id };
1486
1805
  },
1806
+ /**
1807
+ * Send native Plogme rich media with the additive New compatibility field
1808
+ * compatibility sections enabled. The native serializer is retained.
1809
+ */
1810
+ sendNewRichMedia: async (jid, content = {}, quoted, options = {}) => {
1811
+ return socket.sendRichMedia(jid, { ...content, compatibility: 'both' }, quoted, options);
1812
+ },
1487
1813
  /**
1488
1814
  * Send a native AI image/video generation card. The returned messageId
1489
1815
  * is required by updateRichGeneration() for an in-place edit.
@@ -1576,7 +1902,7 @@ export const makeMessagesSocket = (config) => {
1576
1902
  * section present in `content`. Missing sections are intentionally
1577
1903
  * ignored by prepareRichResponseMessage instead of causing a partial
1578
1904
  * response to fail. This is the stable entry point for Plogme/CODY
1579
- * callers that may receive optional text, links, media, products,
1905
+ * callers that may receive optional text, HTML, links, media, products,
1580
1906
  * reels, tables, code, latex, or suggestion data.
1581
1907
  */
1582
1908
  sendPlogmeMessage: async (jid, content = {}, quoted, options = {}) => {
@@ -1807,6 +2133,10 @@ export const makeMessagesSocket = (config) => {
1807
2133
  },
1808
2134
  sendMessage: async (jid, content, options = {}) => {
1809
2135
  const userJid = authState.creds.me.id;
2136
+ const pollValues = content?.poll?.values;
2137
+ if (Array.isArray(pollValues) && pollValues.some(value => value && typeof value === 'object' && value.image)) {
2138
+ return sendImagePoll(jid, content.poll, options);
2139
+ }
1810
2140
  if (content?.groupStatus === true && !isJidGroup(jid)) {
1811
2141
  throw new Boom('groupStatus requires a valid group JID', { statusCode: 400 });
1812
2142
  }
@@ -3025,6 +3355,27 @@ export const makeMessagesSocket = (config) => {
3025
3355
  return fullMsg;
3026
3356
  };
3027
3357
 
3358
+ /**
3359
+ * Send a native group status. `content.private` adds WhatsApp's
3360
+ * statusAudienceMetadata without creating a group message or changing
3361
+ * group membership.
3362
+ */
3363
+ socket.sendGroupStatus = async (jid, content = {}, options = {}) => {
3364
+ if (!jid || !isJidGroup(jid)) {
3365
+ throw new Boom('sendGroupStatus requires a valid group JID', { statusCode: 400 });
3366
+ }
3367
+ if (!content || typeof content !== 'object' || Array.isArray(content)) {
3368
+ throw new Boom('sendGroupStatus content must be a message object', { statusCode: 400 });
3369
+ }
3370
+ const { private: privateAudience, ...statusContent } = content;
3371
+ const audience = privateAudience ?? options.private;
3372
+ return socket.sendMessage(
3373
+ jid,
3374
+ { ...statusContent, groupStatus: true, ...(audience !== undefined ? { private: audience } : {}) },
3375
+ options
3376
+ );
3377
+ };
3378
+
3028
3379
 
3029
3380
  /**
3030
3381
  * Sends an HTML message — renders raw HTML inside the chat bubble.