jagproject 26.3.22 → 26.3.25

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 (206) hide show
  1. package/WAProto/GenerateStatics.sh +3 -4
  2. package/WAProto/WAProto.proto +1215 -511
  3. package/WAProto/fix-imports.js +73 -0
  4. package/WAProto/index.d.ts +14017 -0
  5. package/WAProto/index.js +64857 -145167
  6. package/engine-requirements.js +4 -7
  7. package/lib/Defaults/index.d.ts +74 -0
  8. package/lib/Defaults/index.js +51 -33
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Defaults/wileys-version.json +2 -2
  11. package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
  12. package/lib/Signal/Group/group-session-builder.d.ts +15 -0
  13. package/lib/Signal/Group/group-session-builder.js +5 -3
  14. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  15. package/lib/Signal/Group/group_cipher.js +35 -46
  16. package/lib/Signal/Group/index.d.ts +12 -0
  17. package/lib/Signal/Group/index.js +21 -21
  18. package/lib/Signal/Group/keyhelper.d.ts +11 -0
  19. package/lib/Signal/Group/keyhelper.js +2 -2
  20. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  21. package/lib/Signal/Group/sender-chain-key.js +5 -10
  22. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  23. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  24. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  25. package/lib/Signal/Group/sender-key-message.js +8 -8
  26. package/lib/Signal/Group/sender-key-name.d.ts +18 -0
  27. package/lib/Signal/Group/sender-key-record.d.ts +31 -0
  28. package/lib/Signal/Group/sender-key-record.js +7 -16
  29. package/lib/Signal/Group/sender-key-state.d.ts +39 -0
  30. package/lib/Signal/Group/sender-key-state.js +25 -37
  31. package/lib/Signal/Group/sender-message-key.d.ts +12 -0
  32. package/lib/Signal/Group/sender-message-key.js +2 -2
  33. package/lib/Signal/libsignal.d.ts +5 -0
  34. package/lib/Signal/libsignal.js +358 -54
  35. package/lib/Signal/lid-mapping.d.ts +19 -0
  36. package/lib/Signal/lid-mapping.js +274 -0
  37. package/lib/Socket/Client/index.d.ts +3 -0
  38. package/lib/Socket/Client/index.js +2 -2
  39. package/lib/Socket/Client/types.d.ts +16 -0
  40. package/lib/Socket/Client/types.js +1 -0
  41. package/lib/Socket/Client/websocket.d.ts +13 -0
  42. package/lib/Socket/Client/websocket.js +18 -30
  43. package/lib/Socket/business.d.ts +202 -0
  44. package/lib/Socket/business.js +160 -38
  45. package/lib/Socket/chats.d.ts +111 -0
  46. package/lib/Socket/chats.js +497 -314
  47. package/lib/Socket/communities.d.ts +258 -0
  48. package/lib/Socket/communities.js +438 -0
  49. package/lib/Socket/community.js +333 -0
  50. package/lib/Socket/groups.d.ts +150 -0
  51. package/lib/Socket/groups.js +229 -91
  52. package/lib/Socket/index.d.ts +245 -0
  53. package/lib/Socket/index.js +9 -6
  54. package/lib/Socket/messages-recv.d.ts +187 -0
  55. package/lib/Socket/messages-recv.js +1105 -501
  56. package/lib/Socket/messages-send.d.ts +183 -0
  57. package/lib/Socket/messages-send.js +1184 -501
  58. package/lib/Socket/mex.d.ts +3 -0
  59. package/lib/Socket/mex.js +45 -0
  60. package/lib/Socket/newsletter.d.ts +160 -0
  61. package/lib/Socket/newsletter.js +227 -200
  62. package/lib/Socket/socket.d.ts +55 -0
  63. package/lib/Socket/socket.js +507 -206
  64. package/lib/Socket/usync.js +6 -6
  65. package/lib/Store/index.js +17 -5
  66. package/lib/Store/make-cache-manager-store.js +83 -0
  67. package/lib/Store/make-in-memory-store.js +48 -89
  68. package/lib/Store/make-ordered-dictionary.js +1 -1
  69. package/lib/Types/Auth.d.ts +116 -0
  70. package/lib/Types/Bussines.d.ts +25 -0
  71. package/lib/Types/Bussines.js +2 -0
  72. package/lib/Types/Call.d.ts +15 -0
  73. package/lib/Types/Chat.d.ts +123 -0
  74. package/lib/Types/Chat.js +7 -1
  75. package/lib/Types/Contact.d.ts +24 -0
  76. package/lib/Types/Events.d.ts +237 -0
  77. package/lib/Types/Events.js +1 -0
  78. package/lib/Types/GroupMetadata.d.ts +67 -0
  79. package/lib/Types/Label.d.ts +47 -0
  80. package/lib/Types/Label.js +1 -3
  81. package/lib/Types/LabelAssociation.d.ts +30 -0
  82. package/lib/Types/LabelAssociation.js +1 -3
  83. package/lib/Types/Message.d.ts +305 -0
  84. package/lib/Types/Message.js +9 -5
  85. package/lib/Types/MexUpdates.js +11 -0
  86. package/lib/Types/Newsletter.d.ts +135 -0
  87. package/lib/Types/Newsletter.js +36 -11
  88. package/lib/Types/Product.d.ts +79 -0
  89. package/lib/Types/Signal.d.ts +76 -0
  90. package/lib/Types/Signal.js +1 -0
  91. package/lib/Types/Socket.d.ts +133 -0
  92. package/lib/Types/Socket.js +1 -0
  93. package/lib/Types/State.d.ts +39 -0
  94. package/lib/Types/State.js +12 -0
  95. package/lib/Types/USync.d.ts +26 -0
  96. package/lib/Types/USync.js +1 -0
  97. package/lib/Types/index.d.ts +65 -0
  98. package/lib/Types/index.js +14 -14
  99. package/lib/Utils/audioToBuffer.js +31 -0
  100. package/lib/Utils/auth-utils.d.ts +19 -0
  101. package/lib/Utils/auth-utils.js +222 -123
  102. package/lib/Utils/baileys-event-stream.js +60 -0
  103. package/lib/Utils/browser-utils.d.ts +4 -0
  104. package/lib/Utils/browser-utils.js +38 -29
  105. package/lib/Utils/business.d.ts +23 -0
  106. package/lib/Utils/business.js +54 -48
  107. package/lib/Utils/chat-utils.d.ts +70 -0
  108. package/lib/Utils/chat-utils.js +284 -189
  109. package/lib/Utils/crypto.d.ts +37 -0
  110. package/lib/Utils/crypto.js +16 -41
  111. package/lib/Utils/decode-wa-message.d.ts +48 -0
  112. package/lib/Utils/decode-wa-message.js +128 -48
  113. package/lib/Utils/event-buffer.d.ts +34 -0
  114. package/lib/Utils/event-buffer.js +124 -62
  115. package/lib/Utils/generics.d.ts +91 -0
  116. package/lib/Utils/generics.js +154 -138
  117. package/lib/Utils/history.d.ts +22 -0
  118. package/lib/Utils/history.js +77 -34
  119. package/lib/Utils/identity-change-handler.d.ts +37 -0
  120. package/lib/Utils/identity-change-handler.js +54 -0
  121. package/lib/Utils/index.d.ts +22 -0
  122. package/lib/Utils/index.js +32 -19
  123. package/lib/Utils/link-preview.d.ts +21 -0
  124. package/lib/Utils/link-preview.js +12 -17
  125. package/lib/Utils/logger.d.ts +13 -0
  126. package/lib/Utils/lt-hash.d.ts +8 -0
  127. package/lib/Utils/lt-hash.js +2 -43
  128. package/lib/Utils/make-mutex.d.ts +9 -0
  129. package/lib/Utils/make-mutex.js +21 -27
  130. package/lib/Utils/message-retry-manager.d.ts +110 -0
  131. package/lib/Utils/message-retry-manager.js +143 -45
  132. package/lib/Utils/messages-media.d.ts +130 -0
  133. package/lib/Utils/messages-media.js +429 -502
  134. package/lib/Utils/messages-newsletter.d.ts +84 -0
  135. package/lib/Utils/messages-newsletter.js +295 -0
  136. package/lib/Utils/messages.d.ts +92 -0
  137. package/lib/Utils/messages.js +1099 -400
  138. package/lib/Utils/noise-handler.d.ts +20 -0
  139. package/lib/Utils/noise-handler.js +145 -91
  140. package/lib/Utils/pre-key-manager.d.ts +28 -0
  141. package/lib/Utils/pre-key-manager.js +112 -0
  142. package/lib/Utils/process-message.d.ts +60 -0
  143. package/lib/Utils/process-message.js +316 -184
  144. package/lib/Utils/reporting-utils.d.ts +11 -0
  145. package/lib/Utils/reporting-utils.js +262 -0
  146. package/lib/Utils/resolve-jid.d.ts +43 -0
  147. package/lib/Utils/resolve-jid.js +95 -0
  148. package/lib/Utils/serial-task-queue.js +29 -0
  149. package/lib/Utils/signal.d.ts +34 -0
  150. package/lib/Utils/signal.js +56 -39
  151. package/lib/Utils/streamToBuffer.js +17 -0
  152. package/lib/Utils/sync-action-utils.d.ts +19 -0
  153. package/lib/Utils/sync-action-utils.js +52 -0
  154. package/lib/Utils/tc-token-utils.d.ts +12 -0
  155. package/lib/Utils/tc-token-utils.js +20 -0
  156. package/lib/Utils/use-mongo-file-auth-state.js +71 -0
  157. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  158. package/lib/Utils/use-multi-file-auth-state.js +11 -12
  159. package/lib/Utils/use-single-file-auth-state.js +73 -0
  160. package/lib/Utils/validate-connection.d.ts +11 -0
  161. package/lib/Utils/validate-connection.js +59 -82
  162. package/lib/Utils/wileys-event-stream.js +1 -61
  163. package/lib/WABinary/constants.d.ts +28 -0
  164. package/lib/WABinary/decode.d.ts +7 -0
  165. package/lib/WABinary/decode.js +39 -4
  166. package/lib/WABinary/encode.d.ts +3 -0
  167. package/lib/WABinary/encode.js +17 -11
  168. package/lib/WABinary/generic-utils.d.ts +15 -0
  169. package/lib/WABinary/generic-utils.js +46 -18
  170. package/lib/WABinary/index.d.ts +6 -0
  171. package/lib/WABinary/index.js +9 -5
  172. package/lib/WABinary/jid-utils.d.ts +48 -0
  173. package/lib/WABinary/jid-utils.js +67 -37
  174. package/lib/WABinary/types.d.ts +19 -0
  175. package/lib/WABinary/types.js +34 -0
  176. package/lib/WAM/BinaryInfo.d.ts +9 -0
  177. package/lib/WAM/constants.d.ts +40 -0
  178. package/lib/WAM/constants.js +19183 -11678
  179. package/lib/WAM/encode.d.ts +3 -0
  180. package/lib/WAM/encode.js +15 -17
  181. package/lib/WAM/index.d.ts +4 -0
  182. package/lib/WAM/index.js +3 -3
  183. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  184. package/lib/WAUSync/Protocols/USyncContactProtocol.js +6 -6
  185. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  186. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +9 -9
  187. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  188. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +6 -6
  189. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  190. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -8
  191. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  192. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +18 -17
  193. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  194. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +11 -3
  195. package/lib/WAUSync/Protocols/index.d.ts +5 -0
  196. package/lib/WAUSync/Protocols/index.js +6 -4
  197. package/lib/WAUSync/USyncQuery.d.ts +29 -0
  198. package/lib/WAUSync/USyncQuery.js +38 -30
  199. package/lib/WAUSync/USyncUser.d.ts +13 -0
  200. package/lib/WAUSync/index.d.ts +4 -0
  201. package/lib/WAUSync/index.js +3 -3
  202. package/lib/index.d.ts +12 -0
  203. package/lib/index.js +3 -5
  204. package/package.json +10 -6
  205. package/readme.md +97 -0
  206. package/LICENSE +0 -21
@@ -1,43 +1,164 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
5
35
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
36
+ exports.getQuotedMsg = exports.prepareAlbumMessageContent = exports.patchMessageForMdIfRequired = exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithEventResponse = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getMediaTypeFromContentType = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.hasNonNullishProperty = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
7
37
  exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
38
+ exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage;
8
39
  const boom_1 = require("@hapi/boom");
9
- const axios_1 = __importDefault(require("axios"));
10
40
  const crypto_1 = require("crypto");
11
41
  const fs_1 = require("fs");
12
- const WAProto_1 = require("../../WAProto");
13
- const Defaults_1 = require("../Defaults");
14
- const Types_1 = require("../Types");
15
- const WABinary_1 = require("../WABinary");
16
- const crypto_2 = require("./crypto");
17
- const generics_1 = require("./generics");
18
- const messages_media_1 = require("./messages-media");
42
+ const index_js_1 = require("../../WAProto/index.js");
43
+ const index_js_2 = require("../Defaults/index.js");
44
+ const index_js_3 = require("../Types/index.js");
45
+ const index_js_4 = require("../WABinary/index.js");
46
+ const crypto_js_1 = require("./crypto.js");
47
+ const generics_js_1 = require("./generics.js");
48
+ const messages_media_js_1 = require("./messages-media.js");
49
+ const _require = require;
50
+ const reporting_utils_js_1 = require("./reporting-utils.js");
19
51
  const MIMETYPE_MAP = {
20
52
  image: 'image/jpeg',
21
53
  video: 'video/mp4',
22
54
  document: 'application/pdf',
23
55
  audio: 'audio/ogg; codecs=opus',
24
56
  sticker: 'image/webp',
25
- 'product-catalog-image': 'image/jpeg',
57
+ 'product-catalog-image': 'image/jpeg'
58
+ };
59
+ /** Map ekstensi audio ke mimetype */
60
+ const AUDIO_MIMETYPE_MAP = {
61
+ ogg: 'audio/ogg; codecs=opus',
62
+ oga: 'audio/ogg; codecs=opus',
63
+ opus: 'audio/ogg; codecs=opus',
64
+ mp3: 'audio/mpeg',
65
+ mpeg: 'audio/mpeg',
66
+ mp4: 'audio/mp4',
67
+ m4a: 'audio/mp4',
68
+ aac: 'audio/aac',
69
+ wav: 'audio/wav',
70
+ wave: 'audio/wav',
71
+ flac: 'audio/flac',
72
+ webm: 'audio/webm',
73
+ amr: 'audio/amr',
74
+ '3gp': 'audio/3gpp',
75
+ '3gpp': 'audio/3gpp',
76
+ wma: 'audio/x-ms-wma',
77
+ caf: 'audio/x-caf',
78
+ aiff: 'audio/aiff',
79
+ aif: 'audio/aiff',
80
+ };
81
+ /**
82
+ * Deteksi mimetype audio dari magic bytes buffer.
83
+ * Return null jika tidak dikenali.
84
+ */
85
+ const detectAudioMimetypeFromBuffer = (buf) => {
86
+ if (!buf || buf.length < 12)
87
+ return null;
88
+ // OGG
89
+ if (buf[0] === 0x4F && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53)
90
+ return 'audio/ogg; codecs=opus';
91
+ // MP3 (ID3 tag atau sync bits)
92
+ if ((buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) ||
93
+ (buf[0] === 0xFF && (buf[1] & 0xE0) === 0xE0))
94
+ return 'audio/mpeg';
95
+ // MP4/M4A (ftyp box)
96
+ if (buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70)
97
+ return 'audio/mp4';
98
+ // RIFF/WAV
99
+ if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
100
+ buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45)
101
+ return 'audio/wav';
102
+ // FLAC
103
+ if (buf[0] === 0x66 && buf[1] === 0x4C && buf[2] === 0x61 && buf[3] === 0x43)
104
+ return 'audio/flac';
105
+ // WEBM/MKV
106
+ if (buf[0] === 0x1A && buf[1] === 0x45 && buf[2] === 0xDF && buf[3] === 0xA3)
107
+ return 'audio/webm';
108
+ // AMR
109
+ if (buf[0] === 0x23 && buf[1] === 0x21 && buf[2] === 0x41 && buf[3] === 0x4D &&
110
+ buf[4] === 0x52)
111
+ return 'audio/amr';
112
+ return null;
113
+ };
114
+ /**
115
+ * Deteksi mimetype audio secara otomatis dari media input.
116
+ * Cek: 1) ekstensi URL/path, 2) magic bytes buffer, 3) fallback ke ogg/opus.
117
+ */
118
+ const detectAudioMimetype = async (media) => {
119
+ // Cek ekstensi dari URL atau path string
120
+ if (typeof media === 'string' || (media && typeof media === 'object' && 'url' in media)) {
121
+ const urlStr = typeof media === 'string' ? media : media.url?.toString?.() ?? '';
122
+ // Ambil path tanpa query string, lalu cari semua ekstensi
123
+ const pathOnly = urlStr.split('?')[0];
124
+ // Cek ekstensi terakhir (.m4a, .mp3, dst)
125
+ const extMatch = pathOnly.match(/\.([a-zA-Z0-9]{2,5})(?:[^/]*)?$/);
126
+ if (extMatch) {
127
+ const ext = extMatch[1].toLowerCase();
128
+ if (AUDIO_MIMETYPE_MAP[ext])
129
+ return AUDIO_MIMETYPE_MAP[ext];
130
+ }
131
+ // Fallback: scan semua segmen path untuk ekstensi audio yang dikenal
132
+ // Contoh: ".plus.aac.ep.m4a" → cek tiap segment dari belakang
133
+ const segments = pathOnly.split('.');
134
+ for (let i = segments.length - 1; i >= 0; i--) {
135
+ const seg = segments[i].toLowerCase().split('/')[0].split('?')[0];
136
+ if (AUDIO_MIMETYPE_MAP[seg])
137
+ return AUDIO_MIMETYPE_MAP[seg];
138
+ }
139
+ }
140
+ // Cek magic bytes jika Buffer
141
+ if (Buffer.isBuffer(media)) {
142
+ const detected = detectAudioMimetypeFromBuffer(media);
143
+ if (detected)
144
+ return detected;
145
+ }
146
+ // Fallback: default ogg/opus
147
+ return MIMETYPE_MAP.audio;
26
148
  };
27
149
  const MessageTypeProto = {
28
- 'image': Types_1.WAProto.Message.ImageMessage,
29
- 'video': Types_1.WAProto.Message.VideoMessage,
30
- 'audio': Types_1.WAProto.Message.AudioMessage,
31
- 'sticker': Types_1.WAProto.Message.StickerMessage,
32
- 'document': Types_1.WAProto.Message.DocumentMessage,
150
+ image: index_js_3.WAProto.Message.ImageMessage,
151
+ video: index_js_3.WAProto.Message.VideoMessage,
152
+ audio: index_js_3.WAProto.Message.AudioMessage,
153
+ sticker: index_js_3.WAProto.Message.StickerMessage,
154
+ document: index_js_3.WAProto.Message.DocumentMessage
33
155
  };
34
- const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
35
156
  /**
36
157
  * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
37
158
  * @param text eg. hello https://google.com
38
159
  * @returns the URL, eg. https://google.com
39
160
  */
40
- const extractUrlFromText = (text) => { var _a; return (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0]; };
161
+ const extractUrlFromText = (text) => text.match(index_js_2.URL_REGEX)?.[0];
41
162
  exports.extractUrlFromText = extractUrlFromText;
42
163
  const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
43
164
  const url = (0, exports.extractUrlFromText)(text);
@@ -46,8 +167,9 @@ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
46
167
  const urlInfo = await getUrlInfo(url);
47
168
  return urlInfo;
48
169
  }
49
- catch (error) { // ignore if fails
50
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
170
+ catch (error) {
171
+ // ignore if fails
172
+ logger?.warn({ trace: error.stack }, 'url generation failed');
51
173
  }
52
174
  }
53
175
  };
@@ -69,7 +191,7 @@ const assertColor = async (color) => {
69
191
  const prepareWAMessageMedia = async (message, options) => {
70
192
  const logger = options.logger;
71
193
  let mediaType;
72
- for (const key of Defaults_1.MEDIA_KEYS) {
194
+ for (const key of index_js_2.MEDIA_KEYS) {
73
195
  if (key in message) {
74
196
  mediaType = key;
75
197
  }
@@ -84,113 +206,144 @@ const prepareWAMessageMedia = async (message, options) => {
84
206
  delete uploadData[mediaType];
85
207
  // check if cacheable + generate cache key
86
208
  const cacheableKey = typeof uploadData.media === 'object' &&
87
- ('url' in uploadData.media) &&
209
+ 'url' in uploadData.media &&
88
210
  !!uploadData.media.url &&
89
- !!options.mediaCache && (
90
- // generate the key
91
- mediaType + ':' + uploadData.media.url.toString());
211
+ !!options.mediaCache &&
212
+ mediaType + ':' + uploadData.media.url.toString();
92
213
  if (mediaType === 'document' && !uploadData.fileName) {
93
214
  uploadData.fileName = 'file';
94
215
  }
95
216
  if (!uploadData.mimetype) {
96
217
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
97
218
  }
98
- // check for cache hit
99
219
  if (cacheableKey) {
100
- const mediaBuff = options.mediaCache.get(cacheableKey);
220
+ const mediaBuff = await options.mediaCache.get(cacheableKey);
101
221
  if (mediaBuff) {
102
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
103
- const obj = Types_1.WAProto.Message.decode(mediaBuff);
222
+ logger?.debug({ cacheableKey }, 'got media cache hit');
223
+ const obj = index_js_1.proto.Message.decode(mediaBuff);
104
224
  const key = `${mediaType}Message`;
105
225
  Object.assign(obj[key], { ...uploadData, media: undefined });
106
226
  return obj;
107
227
  }
108
228
  }
229
+ const isNewsletter = !!options.jid && (0, index_js_4.isJidNewsletter)(options.jid);
230
+ if (isNewsletter)
231
+ options.newsletter = true;
109
232
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
110
- const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
111
- (typeof uploadData['jpegThumbnail'] === 'undefined');
112
- const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
113
- const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
114
- const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
115
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
116
- logger,
117
- saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
118
- opts: options.options
119
- });
120
- // url safe Base64 encode the SHA256 hash of the body
121
- const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
122
- const [{ mediaUrl, directPath, handle }] = await Promise.all([
233
+ const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
234
+ const requiresWaveformProcessing = mediaType === 'audio' && (uploadData.ptt === true || !!options.backgroundColor);
235
+ const requiresAudioBackground = options.backgroundColor && mediaType === 'audio';
236
+ const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
237
+ let streamResult;
238
+ try {
239
+ streamResult = await (options.newsletter ? messages_media_js_1.prepareStream : messages_media_js_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
240
+ logger,
241
+ saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
242
+ opts: options.options,
243
+ isPtt: uploadData.ptt,
244
+ });
245
+ }
246
+ catch (streamErr) {
247
+ throw streamErr;
248
+ }
249
+ const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } = streamResult;
250
+ const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 ?? fileSha256).toString('base64');
251
+ const [{ mediaUrl, directPath, handle: uploadHandle }] = await Promise.all([
123
252
  (async () => {
124
- const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
125
- logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
253
+ const result = await options.upload(encWriteStream, {
254
+ fileEncSha256B64,
255
+ mediaType,
256
+ timeoutMs: options.mediaUploadTimeoutMs,
257
+ newsletter: !!options.newsletter
258
+ });
126
259
  return result;
127
260
  })(),
128
261
  (async () => {
129
262
  try {
130
263
  if (requiresThumbnailComputation) {
131
- const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
264
+ const { thumbnail, originalImageDimensions } = await (0, messages_media_js_1.generateThumbnail)(bodyPath, mediaType, options);
132
265
  uploadData.jpegThumbnail = thumbnail;
133
266
  if (!uploadData.width && originalImageDimensions) {
134
267
  uploadData.width = originalImageDimensions.width;
135
268
  uploadData.height = originalImageDimensions.height;
136
- logger === null || logger === void 0 ? void 0 : logger.debug('set dimensions');
269
+ logger?.debug('set dimensions');
137
270
  }
138
- logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
271
+ logger?.debug('generated thumbnail');
139
272
  }
140
273
  if (requiresDurationComputation) {
141
- uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
142
- logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
274
+ try {
275
+ if (bodyPath) {
276
+ uploadData.seconds = await (0, messages_media_js_1.getAudioDuration)(bodyPath, uploadData.mimetype);
277
+ }
278
+ }
279
+ catch (err) {
280
+ uploadData.seconds = 0;
281
+ }
282
+ // Pastikan seconds valid — NaN/undefined bikin WhatsApp tampilkan Loading...
283
+ if (typeof uploadData.seconds !== 'number' || isNaN(uploadData.seconds)) {
284
+ uploadData.seconds = 0;
285
+ }
286
+ logger?.debug('computed audio duration');
143
287
  }
144
288
  if (requiresWaveformProcessing) {
145
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
146
- logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
289
+ try {
290
+ uploadData.waveform = await (0, messages_media_js_1.getAudioWaveform)(bodyPath || encWriteStream, logger);
291
+ }
292
+ catch (err) {
293
+ }
294
+ if (!uploadData.waveform) {
295
+ uploadData.waveform = new Uint8Array([0, 99, 0, 99, 0, 99, 0, 99, 88, 99, 0, 99, 0, 55, 0, 99, 0, 99, 0, 99, 0, 99, 0, 99, 88, 99, 0, 99, 0, 55, 0, 99]);
296
+ }
147
297
  }
148
298
  if (requiresAudioBackground) {
149
299
  uploadData.backgroundArgb = await assertColor(options.backgroundColor);
150
- logger === null || logger === void 0 ? void 0 : logger.debug('computed backgroundColor audio status');
300
+ logger?.debug('computed backgroundColor audio status');
151
301
  }
152
302
  }
153
303
  catch (error) {
154
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
304
+ logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
155
305
  }
156
- })(),
157
- ])
158
- .finally(async () => {
159
- if (!Buffer.isBuffer(encWriteStream)) {
160
- encWriteStream.destroy();
161
- }
162
- // remove tmp files
163
- if (didSaveToTmpPath && bodyPath) {
164
- try {
165
- await fs_1.promises.access(bodyPath);
166
- await fs_1.promises.unlink(bodyPath);
167
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
306
+ })()
307
+ ]).finally(async () => {
308
+ try {
309
+ if (!Buffer.isBuffer(encWriteStream)) {
310
+ encWriteStream.destroy?.();
168
311
  }
169
- catch (error) {
170
- logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
312
+ if (didSaveToTmpPath && bodyPath) {
313
+ await fs_1.promises.unlink(bodyPath).catch(() => { });
171
314
  }
172
315
  }
316
+ catch (error) {
317
+ logger?.warn('failed to remove tmp file');
318
+ }
173
319
  });
174
- const obj = Types_1.WAProto.Message.fromObject({
320
+ const obj = index_js_3.WAProto.Message.fromObject({
175
321
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
176
- url: handle ? undefined : mediaUrl,
322
+ url: uploadHandle ? undefined : mediaUrl,
177
323
  directPath,
178
324
  mediaKey: mediaKey,
179
325
  fileEncSha256: fileEncSha256,
180
326
  fileSha256,
181
327
  fileLength,
182
- mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
328
+ mediaKeyTimestamp: uploadHandle ? undefined : (0, generics_js_1.unixTimestampSeconds)(),
183
329
  ...uploadData,
184
- media: undefined
330
+ media: undefined,
331
+ ...(options?.contextInfo ? { contextInfo: options.contextInfo } : {})
185
332
  })
186
333
  });
187
334
  if (uploadData.ptv) {
188
335
  obj.ptvMessage = obj.videoMessage;
189
336
  delete obj.videoMessage;
190
337
  }
338
+ // Attach uploadHandle so sendMessage can use it as media_id
339
+ if (uploadHandle) {
340
+ obj._uploadHandle = uploadHandle;
341
+ }
342
+ if (mediaType === 'audio') {
343
+ }
191
344
  if (cacheableKey) {
192
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
193
- options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
345
+ logger?.debug({ cacheableKey }, 'set cache');
346
+ await options.mediaCache.set(cacheableKey, index_js_3.WAProto.Message.encode(obj).finish());
194
347
  }
195
348
  return obj;
196
349
  };
@@ -201,13 +354,13 @@ const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
201
354
  ephemeralMessage: {
202
355
  message: {
203
356
  protocolMessage: {
204
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
357
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
205
358
  ephemeralExpiration
206
359
  }
207
360
  }
208
361
  }
209
362
  };
210
- return Types_1.WAProto.Message.fromObject(content);
363
+ return index_js_3.WAProto.Message.fromObject(content);
211
364
  };
212
365
  exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
213
366
  /**
@@ -216,36 +369,46 @@ exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSet
216
369
  * @param options.forceForward will show the message as forwarded even if it is from you
217
370
  */
218
371
  const generateForwardMessageContent = (message, forceForward) => {
219
- var _a;
220
372
  let content = message.message;
221
373
  if (!content) {
222
374
  throw new boom_1.Boom('no content in message', { statusCode: 400 });
223
375
  }
224
376
  // hacky copy
225
377
  content = (0, exports.normalizeMessageContent)(content);
226
- content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish());
378
+ content = index_js_1.proto.Message.decode(index_js_1.proto.Message.encode(content).finish());
227
379
  let key = Object.keys(content)[0];
228
- let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
380
+ let score = content?.[key]?.contextInfo?.forwardingScore || 0;
229
381
  score += message.key.fromMe && !forceForward ? 0 : 1;
230
382
  if (key === 'conversation') {
231
383
  content.extendedTextMessage = { text: content[key] };
232
384
  delete content.conversation;
233
385
  key = 'extendedTextMessage';
234
386
  }
387
+ const key_ = content?.[key];
235
388
  if (score > 0) {
236
- content[key].contextInfo = { forwardingScore: score, isForwarded: true };
389
+ key_.contextInfo = { forwardingScore: score, isForwarded: true };
237
390
  }
238
391
  else {
239
- content[key].contextInfo = {};
392
+ key_.contextInfo = {};
240
393
  }
241
394
  return content;
242
395
  };
243
396
  exports.generateForwardMessageContent = generateForwardMessageContent;
397
+ const hasNonNullishProperty = (message, key) => {
398
+ return (typeof message === 'object' &&
399
+ message !== null &&
400
+ key in message &&
401
+ message[key] !== null &&
402
+ message[key] !== undefined);
403
+ };
404
+ exports.hasNonNullishProperty = hasNonNullishProperty;
405
+ function hasOptionalProperty(obj, key) {
406
+ return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
407
+ }
244
408
  const generateWAMessageContent = async (message, options) => {
245
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
246
- var _p, _q;
409
+ var _a, _b;
247
410
  let m = {};
248
- if ('text' in message) {
411
+ if ((0, exports.hasNonNullishProperty)(message, 'text')) {
249
412
  const extContent = { text: message.text };
250
413
  let urlInfo = message.linkPreview;
251
414
  if (typeof urlInfo === 'undefined') {
@@ -276,43 +439,57 @@ const generateWAMessageContent = async (message, options) => {
276
439
  }
277
440
  m.extendedTextMessage = extContent;
278
441
  }
279
- else if ('contacts' in message) {
442
+ else if ((0, exports.hasNonNullishProperty)(message, 'contacts')) {
280
443
  const contactLen = message.contacts.contacts.length;
281
444
  if (!contactLen) {
282
445
  throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
283
446
  }
284
447
  if (contactLen === 1) {
285
- m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0]);
448
+ m.contactMessage = index_js_3.WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
286
449
  }
287
450
  else {
288
- m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts);
451
+ m.contactsArrayMessage = index_js_3.WAProto.Message.ContactsArrayMessage.create(message.contacts);
289
452
  }
290
453
  }
291
- else if ('location' in message) {
292
- m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
454
+ else if ((0, exports.hasNonNullishProperty)(message, 'location')) {
455
+ if (message.live) {
456
+ m.liveLocationMessage = index_js_3.WAProto.Message.LiveLocationMessage.create(message.location);
457
+ }
458
+ else {
459
+ m.locationMessage = index_js_3.WAProto.Message.LocationMessage.create(message.location);
460
+ }
461
+ const locType = message.live ? 'liveLocationMessage' : 'locationMessage';
462
+ if (m[locType]) {
463
+ m[locType].contextInfo = {
464
+ ...(message.contextInfo || {}),
465
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
466
+ };
467
+ }
293
468
  }
294
- else if ('react' in message) {
469
+ else if ((0, exports.hasNonNullishProperty)(message, 'react')) {
295
470
  if (!message.react.senderTimestampMs) {
296
471
  message.react.senderTimestampMs = Date.now();
297
472
  }
298
- m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
473
+ m.reactionMessage = index_js_3.WAProto.Message.ReactionMessage.create(message.react);
299
474
  }
300
- else if ('delete' in message) {
475
+ else if ((0, exports.hasNonNullishProperty)(message, 'delete')) {
301
476
  m.protocolMessage = {
302
477
  key: message.delete,
303
- type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
478
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.REVOKE
304
479
  };
305
480
  }
306
- else if ('forward' in message) {
481
+ else if ((0, exports.hasNonNullishProperty)(message, 'forward')) {
307
482
  m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
308
483
  }
309
- else if ('disappearingMessagesInChat' in message) {
310
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
311
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
312
- message.disappearingMessagesInChat;
484
+ else if ((0, exports.hasNonNullishProperty)(message, 'disappearingMessagesInChat')) {
485
+ const exp = typeof message.disappearingMessagesInChat === 'boolean'
486
+ ? message.disappearingMessagesInChat
487
+ ? index_js_2.WA_DEFAULT_EPHEMERAL
488
+ : 0
489
+ : message.disappearingMessagesInChat;
313
490
  m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
314
491
  }
315
- else if ('groupInvite' in message) {
492
+ else if ((0, exports.hasNonNullishProperty)(message, 'groupInvite')) {
316
493
  m.groupInviteMessage = {};
317
494
  m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
318
495
  m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
@@ -324,110 +501,207 @@ const generateWAMessageContent = async (message, options) => {
324
501
  if (options.getProfilePicUrl) {
325
502
  const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
326
503
  if (pfpUrl) {
327
- const resp = await axios_1.default.get(pfpUrl, { responseType: 'arraybuffer' });
328
- if (resp.status === 200) {
329
- m.groupInviteMessage.jpegThumbnail = resp.data;
504
+ const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
505
+ if (resp.ok) {
506
+ const buf = Buffer.from(await resp.arrayBuffer());
507
+ m.groupInviteMessage.jpegThumbnail = buf;
330
508
  }
331
509
  }
332
510
  }
333
511
  }
334
- else if ('pin' in message) {
512
+ else if ((0, exports.hasNonNullishProperty)(message, 'pin')) {
335
513
  m.pinInChatMessage = {};
336
514
  m.messageContextInfo = {};
337
- m.pinInChatMessage.key = message.pin;
338
- m.pinInChatMessage.type = message.type;
339
- m.pinInChatMessage.senderTimestampMs = Date.now();
340
- m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
515
+ m.pinInChatMessage.key = message.pin.key;
516
+ m.pinInChatMessage.type = message.pin?.type || 1;
517
+ m.pinInChatMessage.senderTimestampMs = message.pin?.time || Date.now();
518
+ m.messageContextInfo.messageAddOnDurationInSecs = message.pin.type === 1 ? message.pin.time || 86400 : 0;
519
+ m.messageContextInfo.messageAddOnExpiryType = index_js_1.proto.MessageContextInfo.MessageAddonExpiryType.STATIC;
341
520
  }
342
- else if ('keep' in message) {
521
+ else if ((0, exports.hasNonNullishProperty)(message, 'keep')) {
343
522
  m.keepInChatMessage = {};
344
- m.keepInChatMessage.key = message.keep;
345
- m.keepInChatMessage.keepType = message.type;
346
- m.keepInChatMessage.timestampMs = Date.now();
347
- }
348
- else if ('call' in message) {
349
- m = {
350
- scheduledCallCreationMessage: {
351
- scheduledTimestampMs: (_a = message.call.time) !== null && _a !== void 0 ? _a : Date.now(),
352
- callType: (_b = message.call.type) !== null && _b !== void 0 ? _b : 1,
353
- title: message.call.title
354
- }
523
+ m.keepInChatMessage.key = message.keep.key;
524
+ m.keepInChatMessage.keepType = message.keep?.type || 1;
525
+ m.keepInChatMessage.timestampMs = message.keep?.time || Date.now();
526
+ }
527
+ else if ((0, exports.hasNonNullishProperty)(message, 'call')) {
528
+ m.scheduledCallCreationMessage = {};
529
+ m.scheduledCallCreationMessage.scheduledTimestampMs = message.call?.time || Date.now();
530
+ m.scheduledCallCreationMessage.callType = message.call?.type || 1;
531
+ m.scheduledCallCreationMessage.title = message.call?.name || 'Call Creation';
532
+ m.scheduledCallCreationMessage.contextInfo = {
533
+ ...(message.contextInfo || {}),
534
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
355
535
  };
356
536
  }
357
- else if ('paymentInvite' in message) {
358
- m.paymentInviteMessage = {
359
- serviceType: message.paymentInvite.type,
360
- expiryTimestamp: message.paymentInvite.expiry
537
+ else if ((0, exports.hasNonNullishProperty)(message, 'paymentInvite')) {
538
+ m.messageContextInfo = {};
539
+ m.paymentInviteMessage = {};
540
+ m.paymentInviteMessage.expiryTimestamp = message.paymentInvite?.expiry || 0;
541
+ m.paymentInviteMessage.serviceType = message.paymentInvite?.type || 2;
542
+ m.paymentInviteMessage.contextInfo = {
543
+ ...(message.contextInfo || {}),
544
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
361
545
  };
362
546
  }
363
- else if ('buttonReply' in message) {
547
+ else if ((0, exports.hasNonNullishProperty)(message, 'buttonReply')) {
364
548
  switch (message.type) {
549
+ case 'list':
550
+ m.listResponseMessage = {
551
+ title: message.buttonReply.title,
552
+ description: message.buttonReply.description,
553
+ singleSelectReply: {
554
+ selectedRowId: message.buttonReply.rowId
555
+ },
556
+ listType: index_js_1.proto.Message.ListResponseMessage.ListType.SINGLE_SELECT
557
+ };
558
+ break;
365
559
  case 'template':
366
560
  m.templateButtonReplyMessage = {
367
561
  selectedDisplayText: message.buttonReply.displayText,
368
562
  selectedId: message.buttonReply.id,
369
- selectedIndex: message.buttonReply.index,
563
+ selectedIndex: message.buttonReply.index
370
564
  };
371
565
  break;
372
566
  case 'plain':
373
567
  m.buttonsResponseMessage = {
374
568
  selectedButtonId: message.buttonReply.id,
375
569
  selectedDisplayText: message.buttonReply.displayText,
376
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
570
+ type: index_js_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
571
+ };
572
+ break;
573
+ case 'interactive':
574
+ m.interactiveResponseMessage = {
575
+ body: {
576
+ text: message.buttonReply.displayText,
577
+ format: index_js_1.proto.Message.InteractiveResponseMessage.Body.Format.EXTENSIONS_1
578
+ },
579
+ nativeFlowResponseMessage: {
580
+ name: message.buttonReply.nativeFlows.name,
581
+ paramsJson: message.buttonReply.nativeFlows.paramsJson,
582
+ version: message.buttonReply.nativeFlows.version
583
+ }
377
584
  };
378
585
  break;
379
586
  }
380
587
  }
381
- else if ('ptv' in message && message.ptv) {
588
+ else if ((0, exports.hasNonNullishProperty)(message, 'album')) {
589
+ const imageMessages = message.album.filter(item => 'image' in item);
590
+ const videoMessages = message.album.filter(item => 'video' in item);
591
+ m.albumMessage = index_js_3.WAProto.Message.AlbumMessage.fromObject({
592
+ expectedImageCount: imageMessages.length,
593
+ expectedVideoCount: videoMessages.length
594
+ });
595
+ }
596
+ else if ((0, exports.hasNonNullishProperty)(message, 'order')) {
597
+ m.orderMessage = index_js_3.WAProto.Message.OrderMessage.fromObject(message.order);
598
+ m.orderMessage.contextInfo = {
599
+ ...(message.contextInfo || {}),
600
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
601
+ };
602
+ }
603
+ else if ((0, exports.hasNonNullishProperty)(message, 'payment')) {
604
+ const requestPaymentMessage = {
605
+ amount: {
606
+ currencyCode: message.payment?.currency || 'IDR',
607
+ offset: message.payment?.offset || 0,
608
+ value: message.payment?.amount || 999999999
609
+ },
610
+ expiryTimestamp: message.payment?.expiry || 0,
611
+ amount1000: (message.payment?.amount || 999999999) * 1000,
612
+ currencyCodeIso4217: message.payment?.currency || 'IDR',
613
+ requestFrom: message.payment?.from || '0@s.whatsapp.net',
614
+ noteMessage: {
615
+ extendedTextMessage: {
616
+ text: message.payment?.note || 'Notes'
617
+ }
618
+ },
619
+ background: {
620
+ placeholderArgb: message.payment?.image?.placeholderArgb || 4278190080,
621
+ textArgb: message.payment?.image?.textArgb || 4294967295,
622
+ subtextArgb: message.payment?.image?.subtextArgb || 4294967295,
623
+ type: 1
624
+ }
625
+ };
626
+ requestPaymentMessage.noteMessage.extendedTextMessage.contextInfo = {
627
+ ...(message.contextInfo || {}),
628
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
629
+ };
630
+ m.requestPaymentMessage = requestPaymentMessage;
631
+ }
632
+ else if ((0, exports.hasNonNullishProperty)(message, 'pollResult')) {
633
+ if (!Array.isArray(message.pollResult.values)) {
634
+ throw new boom_1.Boom('Invalid pollResult values', { statusCode: 400 });
635
+ }
636
+ const pollResultSnapshotMessage = {
637
+ name: message.pollResult.name,
638
+ pollVotes: message.pollResult.values.map(([optionName, optionVoteCount]) => ({
639
+ optionName,
640
+ optionVoteCount
641
+ }))
642
+ };
643
+ pollResultSnapshotMessage.contextInfo = {
644
+ ...(message.contextInfo || {}),
645
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
646
+ };
647
+ m.pollResultSnapshotMessage = pollResultSnapshotMessage;
648
+ }
649
+ else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
382
650
  const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
383
651
  m.ptvMessage = videoMessage;
384
652
  }
385
- else if ('product' in message) {
653
+ else if ((0, exports.hasNonNullishProperty)(message, 'product')) {
386
654
  const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
387
- m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
655
+ m.productMessage = index_js_3.WAProto.Message.ProductMessage.create({
388
656
  ...message,
389
657
  product: {
390
658
  ...message.product,
391
- productImage: imageMessage,
659
+ productImage: imageMessage
392
660
  }
393
661
  });
394
662
  }
395
- else if ('order' in message) {
396
- m.orderMessage = Types_1.WAProto.Message.OrderMessage.fromObject({
397
- orderId: message.order.id,
398
- thumbnail: message.order.thumbnail,
399
- itemCount: message.order.itemCount,
400
- status: message.order.status,
401
- surface: message.order.surface,
402
- orderTitle: message.order.title,
403
- message: message.order.text,
404
- sellerJid: message.order.seller,
405
- token: message.order.token,
406
- totalAmount1000: message.order.amount,
407
- totalCurrencyCode: message.order.currency
408
- });
409
- }
410
- else if ('listReply' in message) {
663
+ else if ((0, exports.hasNonNullishProperty)(message, 'listReply')) {
411
664
  m.listResponseMessage = { ...message.listReply };
412
665
  }
413
- else if ('poll' in message) {
414
- (_p = message.poll).selectableCount || (_p.selectableCount = 0);
415
- (_q = message.poll).toAnnouncementGroup || (_q.toAnnouncementGroup = false);
666
+ else if ((0, exports.hasNonNullishProperty)(message, 'event')) {
667
+ m.eventMessage = {};
668
+ const startTime = Math.floor(message.event.startDate.getTime() / 1000);
669
+ if (message.event.call && options.getCallLink) {
670
+ const token = await options.getCallLink(message.event.call, { startTime });
671
+ m.eventMessage.joinLink = (message.event.call === 'audio' ? index_js_2.CALL_AUDIO_PREFIX : index_js_2.CALL_VIDEO_PREFIX) + token;
672
+ }
673
+ m.messageContextInfo = {
674
+ // encKey
675
+ messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32)
676
+ };
677
+ m.eventMessage.name = message.event.name;
678
+ m.eventMessage.description = message.event.description;
679
+ m.eventMessage.startTime = startTime;
680
+ m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
681
+ m.eventMessage.isCanceled = message.event.isCancelled ?? false;
682
+ m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
683
+ m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
684
+ m.eventMessage.location = message.event.location;
685
+ }
686
+ else if ((0, exports.hasNonNullishProperty)(message, 'poll')) {
687
+ (_a = message.poll).selectableCount || (_a.selectableCount = 0);
688
+ (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
416
689
  if (!Array.isArray(message.poll.values)) {
417
690
  throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
418
691
  }
419
- if (message.poll.selectableCount < 0
420
- || message.poll.selectableCount > message.poll.values.length) {
421
- throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, { statusCode: 400 });
692
+ if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
693
+ throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
694
+ statusCode: 400
695
+ });
422
696
  }
423
697
  m.messageContextInfo = {
424
698
  // encKey
425
- messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
699
+ messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32)
426
700
  };
427
701
  const pollCreationMessage = {
428
702
  name: message.poll.name,
429
703
  selectableOptionsCount: message.poll.selectableCount,
430
- options: message.poll.values.map(optionName => ({ optionName })),
704
+ options: message.poll.values.map(optionName => ({ optionName }))
431
705
  };
432
706
  if (message.poll.toAnnouncementGroup) {
433
707
  // poll v2 is for community announcement groups (single select and multiple)
@@ -435,7 +709,7 @@ const generateWAMessageContent = async (message, options) => {
435
709
  }
436
710
  else {
437
711
  if (message.poll.selectableCount === 1) {
438
- // poll v3 is for single select polls
712
+ //poll v3 is for single select polls
439
713
  m.pollCreationMessageV3 = pollCreationMessage;
440
714
  }
441
715
  else {
@@ -444,169 +718,340 @@ const generateWAMessageContent = async (message, options) => {
444
718
  }
445
719
  }
446
720
  }
447
- else if ('event' in message) {
448
- m.messageContextInfo = {
449
- messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32),
450
- };
451
- m.eventMessage = { ...message.event };
452
- }
453
- else if ('inviteAdmin' in message) {
454
- m.newsletterAdminInviteMessage = {};
455
- m.newsletterAdminInviteMessage.inviteExpiration = message.inviteAdmin.inviteExpiration;
456
- m.newsletterAdminInviteMessage.caption = message.inviteAdmin.text;
457
- m.newsletterAdminInviteMessage.newsletterJid = message.inviteAdmin.jid;
458
- m.newsletterAdminInviteMessage.newsletterName = message.inviteAdmin.subject;
459
- m.newsletterAdminInviteMessage.jpegThumbnail = message.inviteAdmin.thumbnail;
460
- }
461
- else if ('requestPayment' in message) {
462
- const sticker = ((_c = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _c === void 0 ? void 0 : _c.sticker) ?
463
- await (0, exports.prepareWAMessageMedia)({ sticker: (_d = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _d === void 0 ? void 0 : _d.sticker, ...options }, options)
464
- : null;
465
- let notes = {};
466
- if ((_e = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _e === void 0 ? void 0 : _e.sticker) {
467
- notes = {
468
- stickerMessage: {
469
- ...sticker === null || sticker === void 0 ? void 0 : sticker.stickerMessage,
470
- contextInfo: (_f = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _f === void 0 ? void 0 : _f.contextInfo
471
- }
472
- };
721
+ else if ((0, exports.hasNonNullishProperty)(message, 'stickerPack')) {
722
+ const { zip } = _require('fflate');
723
+ const { stickers, cover, name, publisher, packId, description } = message.stickerPack;
724
+ // ── Validasi jumlah sticker ───────────────────────────────────────────
725
+ if (stickers.length > 60) {
726
+ throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
473
727
  }
474
- else if (message.requestPayment.note) {
475
- notes = {
476
- extendedTextMessage: {
477
- text: message.requestPayment.note,
478
- contextInfo: (_g = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _g === void 0 ? void 0 : _g.contextInfo,
728
+ if (stickers.length === 0) {
729
+ throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
730
+ }
731
+ const stickerPackId = packId || (0, generics_js_1.generateMessageIDV2)();
732
+ const [_sharp, _jimp] = await Promise.all([Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => null), Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => null)]);
733
+ const lib = _sharp ? { sharp: _sharp } : _jimp ? { jimp: _jimp } : null;
734
+ if (!lib)
735
+ throw new boom_1.Boom('No image processing library available (install sharp or jimp)');
736
+ // ── Helper: deteksi WebP dari magic bytes ─────────────────────────────
737
+ const isWebPBuffer = (buf) => (buf.length >= 12 &&
738
+ buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
739
+ buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50);
740
+ // ── Helper: deteksi animasi WebP (VP8X/ANIM/ANMF chunks) ─────────────
741
+ const isAnimatedWebP = (buf) => {
742
+ if (!isWebPBuffer(buf))
743
+ return false;
744
+ let offset = 12;
745
+ while (offset < buf.length - 8) {
746
+ const fourCC = buf.toString('ascii', offset, offset + 4);
747
+ const chunkSize = buf.readUInt32LE(offset + 4);
748
+ if (fourCC === 'VP8X') {
749
+ const flagsOffset = offset + 8;
750
+ if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02))
751
+ return true;
752
+ }
753
+ else if (fourCC === 'ANIM' || fourCC === 'ANMF') {
754
+ return true;
479
755
  }
756
+ offset += 8 + chunkSize + (chunkSize % 2);
757
+ }
758
+ return false;
759
+ };
760
+ // ── Step 1: proses & zip semua sticker ────────────────────────────────
761
+ const stickerData = {};
762
+ const stickerPromises = stickers.map(async (s, i) => {
763
+ const { stream } = await (0, messages_media_js_1.getStream)(s.data || s.sticker);
764
+ const buffer = await (0, messages_media_js_1.toBuffer)(stream);
765
+ let webpBuffer;
766
+ let isAnimated = false;
767
+ if (isWebPBuffer(buffer)) {
768
+ webpBuffer = buffer;
769
+ isAnimated = isAnimatedWebP(buffer);
770
+ }
771
+ else if ('sharp' in lib && lib.sharp) {
772
+ webpBuffer = await lib.sharp.default(buffer).webp().toBuffer();
773
+ }
774
+ else {
775
+ throw new boom_1.Boom('No image processing library (sharp) available for converting sticker to WebP. ' +
776
+ 'Either install sharp or provide stickers in WebP format.');
777
+ }
778
+ if (webpBuffer.length > 1024 * 1024) {
779
+ throw new boom_1.Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
780
+ }
781
+ const hash = (0, crypto_js_1.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
782
+ const fileName = `${hash}.webp`;
783
+ stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
784
+ return {
785
+ fileName,
786
+ mimetype: 'image/webp',
787
+ isAnimated,
788
+ emojis: s.emojis || [],
789
+ accessibilityLabel: s.accessibilityLabel || ''
480
790
  };
791
+ });
792
+ const stickerMetadata = await Promise.all(stickerPromises);
793
+ // ── Step 2: proses cover & masukkan ke dalam ZIP ──────────────────────
794
+ const trayIconFileName = `${stickerPackId}.webp`;
795
+ const coverBuffer = await (0, messages_media_js_1.toBuffer)((await (0, messages_media_js_1.getStream)(cover)).stream);
796
+ let coverWebpBuffer;
797
+ if (isWebPBuffer(coverBuffer)) {
798
+ coverWebpBuffer = coverBuffer;
799
+ }
800
+ else if ('sharp' in lib && lib.sharp) {
801
+ coverWebpBuffer = await lib.sharp.default(coverBuffer).webp().toBuffer();
481
802
  }
482
803
  else {
483
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
484
- }
485
- m.requestPaymentMessage = Types_1.WAProto.Message.RequestPaymentMessage.fromObject({
486
- expiryTimestamp: message.requestPayment.expiry,
487
- amount1000: message.requestPayment.amount,
488
- currencyCodeIso4217: message.requestPayment.currency,
489
- requestFrom: message.requestPayment.from,
490
- noteMessage: { ...notes },
491
- background: (_h = message.requestPayment.background) !== null && _h !== void 0 ? _h : null,
804
+ throw new boom_1.Boom('No image processing library (sharp) available for converting cover to WebP. ' +
805
+ 'Either install sharp or provide cover in WebP format.');
806
+ }
807
+ stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
808
+ // ── Step 3: buat ZIP buffer ───────────────────────────────────────────
809
+ const zipBuffer = await new Promise((resolve, reject) => {
810
+ zip(stickerData, (err, data) => {
811
+ if (err)
812
+ reject(err);
813
+ else
814
+ resolve(Buffer.from(data));
815
+ });
816
+ });
817
+ // ── Step 4: encrypt ZIP (generate random mediaKey) ────────────────────
818
+ const stickerPackUpload = await (0, messages_media_js_1.encryptedStream)(zipBuffer, 'sticker-pack', {
819
+ logger: options.logger,
820
+ opts: options.options
492
821
  });
822
+ // ── Step 5: upload ZIP ────────────────────────────────────────────────
823
+ const stickerPackUploadResult = await options.upload(stickerPackUpload.encWriteStream, {
824
+ fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
825
+ mediaType: 'sticker-pack',
826
+ timeoutMs: options.mediaUploadTimeoutMs
827
+ });
828
+ // ── Step 6: build stickerPackMessage ──────────────────────────────────
829
+ m.stickerPackMessage = {
830
+ name,
831
+ publisher,
832
+ stickerPackId,
833
+ packDescription: description,
834
+ stickerPackOrigin: index_js_3.WAProto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
835
+ stickerPackSize: zipBuffer.length,
836
+ stickers: stickerMetadata,
837
+ fileSha256: stickerPackUpload.fileSha256,
838
+ fileEncSha256: stickerPackUpload.fileEncSha256,
839
+ mediaKey: stickerPackUpload.mediaKey,
840
+ directPath: stickerPackUploadResult.directPath,
841
+ fileLength: stickerPackUpload.fileLength,
842
+ mediaKeyTimestamp: (0, generics_js_1.unixTimestampSeconds)(),
843
+ trayIconFileName
844
+ };
845
+ // ── Step 7: generate & upload thumbnail (pakai mediaKey yang sama) ────
846
+ try {
847
+ let thumbnailBuffer;
848
+ if ('sharp' in lib && lib.sharp) {
849
+ thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
850
+ }
851
+ else if ('jimp' in lib && lib.jimp) {
852
+ const jimpImage = await (lib.jimp.Jimp || lib.jimp.default).read(coverBuffer);
853
+ thumbnailBuffer = await jimpImage.resize({ w: 252, h: 252 }).getBuffer('image/jpeg');
854
+ }
855
+ else {
856
+ throw new Error('No image processing library available for thumbnail generation');
857
+ }
858
+ if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
859
+ throw new Error('Failed to generate thumbnail buffer');
860
+ }
861
+ const thumbUpload = await (0, messages_media_js_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
862
+ logger: options.logger,
863
+ opts: options.options,
864
+ mediaKey: stickerPackUpload.mediaKey
865
+ });
866
+ const thumbUploadResult = await options.upload(thumbUpload.encWriteStream, {
867
+ fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
868
+ mediaType: 'thumbnail-sticker-pack',
869
+ timeoutMs: options.mediaUploadTimeoutMs
870
+ });
871
+ Object.assign(m.stickerPackMessage, {
872
+ thumbnailDirectPath: thumbUploadResult.directPath,
873
+ thumbnailSha256: thumbUpload.fileSha256,
874
+ thumbnailEncSha256: thumbUpload.fileEncSha256,
875
+ thumbnailHeight: 252,
876
+ thumbnailWidth: 252,
877
+ imageDataHash: (0, crypto_js_1.sha256)(thumbnailBuffer).toString('base64')
878
+ });
879
+ }
880
+ catch (e) {
881
+ options.logger?.warn?.(`Thumbnail generation failed: ${e}`);
882
+ }
883
+ m.stickerPackMessage.contextInfo = {
884
+ ...(message.contextInfo || {}),
885
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
886
+ };
493
887
  }
494
- else if ('sharePhoneNumber' in message) {
888
+ else if ((0, exports.hasNonNullishProperty)(message, 'adminInvite')) {
889
+ m.newsletterAdminInviteMessage = {};
890
+ m.newsletterAdminInviteMessage.newsletterJid = message.adminInvite.jid;
891
+ m.newsletterAdminInviteMessage.newsletterName = message.adminInvite.name;
892
+ m.newsletterAdminInviteMessage.caption = message.adminInvite.caption;
893
+ m.newsletterAdminInviteMessage.inviteExpiration = message.adminInvite.expiration;
894
+ if (message.adminInvite.jpegThumbnail) {
895
+ m.newsletterAdminInviteMessage.jpegThumbnail = message.adminInvite.jpegThumbnail;
896
+ }
897
+ else if (options.getProfilePicUrl) {
898
+ try {
899
+ const pfpUrl = await options.getProfilePicUrl(message.adminInvite.jid);
900
+ if (pfpUrl) {
901
+ const { thumbnail } = await (0, messages_media_js_1.generateThumbnail)(pfpUrl, 'image');
902
+ m.newsletterAdminInviteMessage.jpegThumbnail = thumbnail;
903
+ }
904
+ }
905
+ catch (_) { }
906
+ }
907
+ m.newsletterAdminInviteMessage.contextInfo = {
908
+ ...(message.contextInfo || {}),
909
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
910
+ };
911
+ }
912
+ else if ((0, exports.hasNonNullishProperty)(message, 'sharePhoneNumber')) {
495
913
  m.protocolMessage = {
496
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
914
+ type: index_js_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
497
915
  };
498
916
  }
499
- else if ('requestPhoneNumber' in message) {
917
+ else if ((0, exports.hasNonNullishProperty)(message, 'requestPhoneNumber')) {
500
918
  m.requestPhoneNumberMessage = {};
501
919
  }
502
- else if ('album' in message) {
503
- const imageMessages = message.album.filter(item => 'image' in item);
504
- const videoMessages = message.album.filter(item => 'video' in item);
505
- m.albumMessage = WAProto_1.proto.Message.AlbumMessage.fromObject({
506
- expectedImageCount: imageMessages.length,
507
- expectedVideoCount: videoMessages.length,
508
- });
920
+ else if ((0, exports.hasNonNullishProperty)(message, 'limitSharing')) {
921
+ m.protocolMessage = {
922
+ type: index_js_1.proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
923
+ limitSharing: {
924
+ sharingLimited: message.limitSharing === true,
925
+ trigger: 1,
926
+ limitSharingSettingTimestamp: Date.now(),
927
+ initiatedByMe: true
928
+ }
929
+ };
930
+ }
931
+ else if ('interactiveMessage' in message && !!message.interactiveMessage) {
932
+ // ── Passthrough interactiveMessage raw object ──────────────────────
933
+ // Must be BEFORE the else block to avoid hitting prepareWAMessageMedia
934
+ // which throws 'Invalid media type' for interactiveMessage keys.
935
+ m = { interactiveMessage: message.interactiveMessage };
509
936
  }
510
937
  else {
511
938
  m = await (0, exports.prepareWAMessageMedia)(message, options);
512
939
  }
513
- if ('buttons' in message && !!message.buttons) {
940
+ if ('sections' in message && !!message.sections) {
941
+ const listMessage = {
942
+ title: message.title,
943
+ buttonText: message.buttonText,
944
+ footerText: message.footer,
945
+ description: message.text,
946
+ sections: message.sections,
947
+ listType: index_js_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
948
+ };
949
+ listMessage.contextInfo = {
950
+ ...(message.contextInfo || {}),
951
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
952
+ };
953
+ m = { listMessage };
954
+ }
955
+ else if ('productList' in message && !!message.productList) {
956
+ const thumbnail = message.thumbnail ? await (0, messages_media_js_1.generateThumbnail)(message.thumbnail, 'image') : null;
957
+ const listMessage = {
958
+ title: message.title,
959
+ buttonText: message.buttonText,
960
+ footerText: message.footer,
961
+ description: message.text,
962
+ productListInfo: {
963
+ productSections: message.productList,
964
+ headerImage: {
965
+ productId: message.productList[0].products[0].productId,
966
+ jpegThumbnail: thumbnail?.thumbnail || null
967
+ },
968
+ businessOwnerJid: message.businessOwnerJid
969
+ },
970
+ listType: index_js_1.proto.Message.ListMessage.ListType.PRODUCT_LIST
971
+ };
972
+ listMessage.contextInfo = {
973
+ ...(message.contextInfo || {}),
974
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
975
+ };
976
+ m = { listMessage };
977
+ }
978
+ else if ('buttons' in message && !!message.buttons) {
514
979
  const buttonsMessage = {
515
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
980
+ buttons: message.buttons.map(b => ({ ...b, type: index_js_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
516
981
  };
517
982
  if ('text' in message) {
518
983
  buttonsMessage.contentText = message.text;
519
- buttonsMessage.headerType = ButtonType.EMPTY;
984
+ buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType.EMPTY;
520
985
  }
521
986
  else {
522
987
  if ('caption' in message) {
523
988
  buttonsMessage.contentText = message.caption;
524
989
  }
525
990
  const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
526
- buttonsMessage.headerType = ButtonType[type];
991
+ buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType[type];
527
992
  Object.assign(buttonsMessage, m);
528
993
  }
529
- if ('title' in message && !!message.title) {
530
- buttonsMessage.text = message.title,
531
- buttonsMessage.headerType = ButtonType.TEXT;
532
- }
533
994
  if ('footer' in message && !!message.footer) {
534
995
  buttonsMessage.footerText = message.footer;
535
996
  }
536
- if ('contextInfo' in message && !!message.contextInfo) {
537
- buttonsMessage.contextInfo = message.contextInfo;
538
- }
539
- if ('mentions' in message && !!message.mentions) {
540
- buttonsMessage.contextInfo = { mentionedJid: message.mentions };
997
+ if ('title' in message && !!message.title) {
998
+ buttonsMessage.text = message.title;
999
+ buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType.TEXT;
541
1000
  }
1001
+ buttonsMessage.contextInfo = {
1002
+ ...(message.contextInfo || {}),
1003
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
1004
+ };
542
1005
  m = { buttonsMessage };
543
1006
  }
544
1007
  else if ('templateButtons' in message && !!message.templateButtons) {
545
- const msg = {
546
- hydratedButtons: message.hasOwnProperty("templateButtons") ? message.templateButtons : message.templateButtons
1008
+ const hydratedTemplate = {
1009
+ hydratedButtons: message.templateButtons
547
1010
  };
548
1011
  if ('text' in message) {
549
- msg.hydratedContentText = message.text;
1012
+ hydratedTemplate.hydratedContentText = message.text;
550
1013
  }
551
1014
  else {
552
1015
  if ('caption' in message) {
553
- msg.hydratedContentText = message.caption;
1016
+ hydratedTemplate.hydratedContentText = message.caption;
554
1017
  }
555
- Object.assign(msg, m);
1018
+ Object.assign(hydratedTemplate, m);
556
1019
  }
557
1020
  if ('footer' in message && !!message.footer) {
558
- msg.hydratedFooterText = message.footer;
1021
+ hydratedTemplate.hydratedFooterText = message.footer;
559
1022
  }
560
- m = {
561
- templateMessage: {
562
- fourRowTemplate: msg,
563
- hydratedTemplate: msg
564
- }
565
- };
566
- }
567
- if ('sections' in message && !!message.sections) {
568
- const listMessage = {
569
- sections: message.sections,
570
- buttonText: message.buttonText,
571
- title: message.title,
572
- footerText: message.footer,
573
- description: message.text,
574
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
1023
+ hydratedTemplate.contextInfo = {
1024
+ ...(message.contextInfo || {}),
1025
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
575
1026
  };
576
- m = { listMessage };
1027
+ m = { templateMessage: { fourRowTemplate: hydratedTemplate, hydratedTemplate } };
577
1028
  }
578
- if ('interactiveButtons' in message && !!message.interactiveButtons) {
1029
+ else if ('interactiveButtons' in message && !!message.interactiveButtons) {
579
1030
  const interactiveMessage = {
580
- nativeFlowMessage: Types_1.WAProto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
1031
+ nativeFlowMessage: index_js_1.proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
581
1032
  buttons: message.interactiveButtons,
582
1033
  })
583
1034
  };
584
1035
  if ('text' in message) {
585
- interactiveMessage.body = {
586
- text: message.text
587
- };
1036
+ interactiveMessage.body = { text: message.text };
588
1037
  }
589
1038
  else if ('caption' in message) {
590
- interactiveMessage.body = {
591
- text: message.caption
592
- };
1039
+ interactiveMessage.body = { text: message.caption };
593
1040
  interactiveMessage.header = {
594
1041
  title: message.title,
595
1042
  subtitle: message.subtitle,
596
- hasMediaAttachment: (_j = message === null || message === void 0 ? void 0 : message.media) !== null && _j !== void 0 ? _j : false,
1043
+ hasMediaAttachment: message?.media ?? false,
597
1044
  };
598
1045
  Object.assign(interactiveMessage.header, m);
599
1046
  }
600
1047
  if ('footer' in message && !!message.footer) {
601
- interactiveMessage.footer = {
602
- text: message.footer
603
- };
1048
+ interactiveMessage.footer = { text: message.footer };
604
1049
  }
605
1050
  if ('title' in message && !!message.title) {
606
1051
  interactiveMessage.header = {
607
1052
  title: message.title,
608
1053
  subtitle: message.subtitle,
609
- hasMediaAttachment: (_k = message === null || message === void 0 ? void 0 : message.media) !== null && _k !== void 0 ? _k : false,
1054
+ hasMediaAttachment: message?.media ?? false,
610
1055
  };
611
1056
  Object.assign(interactiveMessage.header, m);
612
1057
  }
@@ -618,39 +1063,33 @@ const generateWAMessageContent = async (message, options) => {
618
1063
  }
619
1064
  m = { interactiveMessage };
620
1065
  }
621
- if ('shop' in message && !!message.shop) {
1066
+ else if ('shop' in message && !!message.shop) {
622
1067
  const interactiveMessage = {
623
- shopStorefrontMessage: Types_1.WAProto.Message.InteractiveMessage.ShopMessage.fromObject({
1068
+ shopStorefrontMessage: index_js_1.proto.Message.InteractiveMessage.ShopMessage.fromObject({
624
1069
  surface: message.shop,
625
1070
  id: message.id
626
1071
  })
627
1072
  };
628
1073
  if ('text' in message) {
629
- interactiveMessage.body = {
630
- text: message.text
631
- };
1074
+ interactiveMessage.body = { text: message.text };
632
1075
  }
633
1076
  else if ('caption' in message) {
634
- interactiveMessage.body = {
635
- text: message.caption
636
- };
1077
+ interactiveMessage.body = { text: message.caption };
637
1078
  interactiveMessage.header = {
638
1079
  title: message.title,
639
1080
  subtitle: message.subtitle,
640
- hasMediaAttachment: (_l = message === null || message === void 0 ? void 0 : message.media) !== null && _l !== void 0 ? _l : false,
1081
+ hasMediaAttachment: message?.media ?? false,
641
1082
  };
642
1083
  Object.assign(interactiveMessage.header, m);
643
1084
  }
644
1085
  if ('footer' in message && !!message.footer) {
645
- interactiveMessage.footer = {
646
- text: message.footer
647
- };
1086
+ interactiveMessage.footer = { text: message.footer };
648
1087
  }
649
1088
  if ('title' in message && !!message.title) {
650
1089
  interactiveMessage.header = {
651
1090
  title: message.title,
652
1091
  subtitle: message.subtitle,
653
- hasMediaAttachment: (_m = message === null || message === void 0 ? void 0 : message.media) !== null && _m !== void 0 ? _m : false,
1092
+ hasMediaAttachment: message?.media ?? false,
654
1093
  };
655
1094
  Object.assign(interactiveMessage.header, m);
656
1095
  }
@@ -662,30 +1101,143 @@ const generateWAMessageContent = async (message, options) => {
662
1101
  }
663
1102
  m = { interactiveMessage };
664
1103
  }
665
- if ('viewOnce' in message && !!message.viewOnce) {
666
- m = { viewOnceMessage: { message: m } };
1104
+ else if ('collection' in message && !!message.collection) {
1105
+ const interactiveMessage = {
1106
+ collectionMessage: {
1107
+ bizJid: message.collection.bizJid,
1108
+ id: message.collection.id,
1109
+ messageVersion: message?.collection?.version
1110
+ }
1111
+ };
1112
+ if ('text' in message) {
1113
+ interactiveMessage.body = { text: message.text };
1114
+ interactiveMessage.header = {
1115
+ title: message.title,
1116
+ subtitle: message.subtitle,
1117
+ hasMediaAttachment: false
1118
+ };
1119
+ }
1120
+ else {
1121
+ if ('caption' in message) {
1122
+ interactiveMessage.body = { text: message.caption };
1123
+ interactiveMessage.header = {
1124
+ title: message.title,
1125
+ subtitle: message.subtitle,
1126
+ hasMediaAttachment: message.hasMediaAttachment ? message.hasMediaAttachment : false,
1127
+ ...Object.assign(interactiveMessage, m)
1128
+ };
1129
+ }
1130
+ }
1131
+ if ('footer' in message && !!message.footer) {
1132
+ interactiveMessage.footer = { text: message.footer };
1133
+ }
1134
+ interactiveMessage.contextInfo = {
1135
+ ...(message.contextInfo || {}),
1136
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
1137
+ };
1138
+ m = { interactiveMessage };
667
1139
  }
668
- if ('mentions' in message && ((_o = message.mentions) === null || _o === void 0 ? void 0 : _o.length)) {
669
- const [messageType] = Object.keys(m);
670
- m[messageType].contextInfo = m[messageType] || {};
671
- m[messageType].contextInfo.mentionedJid = message.mentions;
1140
+ else if ('cards' in message && !!message.cards) {
1141
+ const slides = await Promise.all(message.cards.map(async (slide) => {
1142
+ const { image, video, product, title, body, footer, buttons } = slide;
1143
+ let header;
1144
+ if (product) {
1145
+ const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: product.productImage, ...options }, options);
1146
+ header = {
1147
+ productMessage: {
1148
+ product: {
1149
+ ...product,
1150
+ productImage: imageMessage,
1151
+ },
1152
+ ...slide
1153
+ }
1154
+ };
1155
+ }
1156
+ else if (image) {
1157
+ header = await (0, exports.prepareWAMessageMedia)({ image: image, ...options }, options);
1158
+ }
1159
+ else if (video) {
1160
+ header = await (0, exports.prepareWAMessageMedia)({ video: video, ...options }, options);
1161
+ }
1162
+ return {
1163
+ header: {
1164
+ title,
1165
+ hasMediaAttachment: true,
1166
+ ...header
1167
+ },
1168
+ body: { text: body },
1169
+ footer: { text: footer },
1170
+ nativeFlowMessage: { buttons }
1171
+ };
1172
+ }));
1173
+ const interactiveMessage = {
1174
+ carouselMessage: { cards: slides }
1175
+ };
1176
+ if ('text' in message) {
1177
+ interactiveMessage.body = { text: message.text };
1178
+ interactiveMessage.header = {
1179
+ title: message.title,
1180
+ subtitle: message.subtitle,
1181
+ hasMediaAttachment: false
1182
+ };
1183
+ }
1184
+ if ('footer' in message && !!message.footer) {
1185
+ interactiveMessage.footer = { text: message.footer };
1186
+ }
1187
+ interactiveMessage.contextInfo = {
1188
+ ...(message.contextInfo || {}),
1189
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
1190
+ };
1191
+ m = { interactiveMessage };
1192
+ }
1193
+ if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
1194
+ m = { ephemeralMessage: { message: m } };
1195
+ }
1196
+ if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
1197
+ m = { viewOnceMessageV2: { message: m } };
1198
+ }
1199
+ if (hasOptionalProperty(message, 'viewOnceExt') && !!message.viewOnceExt) {
1200
+ m = { viewOnceMessageV2Extension: { message: m } };
1201
+ }
1202
+ if (hasOptionalProperty(message, 'mentions') && message.mentions?.length) {
1203
+ const messageType = Object.keys(m)[0];
1204
+ const key = m[messageType];
1205
+ if ('contextInfo' in key && !!key.contextInfo) {
1206
+ key.contextInfo.mentionedJid = message.mentions;
1207
+ }
1208
+ else if (key) {
1209
+ key.contextInfo = {
1210
+ mentionedJid: message.mentions
1211
+ };
1212
+ }
672
1213
  }
673
- if ('edit' in message) {
1214
+ if (hasOptionalProperty(message, 'edit')) {
674
1215
  m = {
675
1216
  protocolMessage: {
676
1217
  key: message.edit,
677
1218
  editedMessage: m,
678
1219
  timestampMs: Date.now(),
679
- type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
1220
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
680
1221
  }
681
1222
  };
682
1223
  }
683
- if ('contextInfo' in message && !!message.contextInfo) {
684
- const [messageType] = Object.keys(m);
685
- m[messageType] = m[messageType] || {};
686
- m[messageType].contextInfo = message.contextInfo;
1224
+ if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
1225
+ const messageType = Object.keys(m)[0];
1226
+ const key = m[messageType];
1227
+ if ('contextInfo' in key && !!key.contextInfo) {
1228
+ key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
1229
+ }
1230
+ else if (key) {
1231
+ key.contextInfo = message.contextInfo;
1232
+ }
1233
+ }
1234
+ if ((0, reporting_utils_js_1.shouldIncludeReportingToken)(m) && !options.newsletter) {
1235
+ m.messageContextInfo = m.messageContextInfo || {};
1236
+ if (!m.messageContextInfo.messageSecret) {
1237
+ m.messageContextInfo.messageSecret = (0, crypto_1.randomBytes)(32);
1238
+ }
687
1239
  }
688
- return Types_1.WAProto.Message.fromObject(m);
1240
+ return index_js_3.WAProto.Message.create(m);
689
1241
  };
690
1242
  exports.generateWAMessageContent = generateWAMessageContent;
691
1243
  const generateWAMessageFromContent = (jid, message, options) => {
@@ -696,68 +1248,72 @@ const generateWAMessageFromContent = (jid, message, options) => {
696
1248
  }
697
1249
  const innerMessage = (0, exports.normalizeMessageContent)(message);
698
1250
  const key = (0, exports.getContentType)(innerMessage);
699
- const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
1251
+ const timestamp = (0, generics_js_1.unixTimestampSeconds)(options.timestamp);
700
1252
  const { quoted, userJid } = options;
701
- // only set quoted if isn't a newsletter message
702
- if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
703
- const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
1253
+ if (quoted && !(0, index_js_4.isJidNewsletter)(jid)) {
1254
+ const participant = quoted.key.fromMe
1255
+ ? userJid // TODO: Add support for LIDs
1256
+ : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
704
1257
  let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
705
1258
  const msgType = (0, exports.getContentType)(quotedMsg);
706
1259
  // strip any redundant properties
707
- if (quotedMsg) {
708
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
709
- const quotedContent = quotedMsg[msgType];
710
- if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
711
- delete quotedContent.contextInfo;
712
- }
713
- const contextInfo = innerMessage[key].contextInfo || {};
714
- contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
715
- contextInfo.stanzaId = quoted.key.id;
716
- contextInfo.quotedMessage = quotedMsg;
717
- // if a participant is quoted, then it must be a group
718
- // hence, remoteJid of group must also be entered
719
- if (jid !== quoted.key.remoteJid) {
720
- contextInfo.remoteJid = quoted.key.remoteJid;
721
- }
1260
+ quotedMsg = index_js_1.proto.Message.create({ [msgType]: quotedMsg[msgType] });
1261
+ const quotedContent = quotedMsg[msgType];
1262
+ if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
1263
+ delete quotedContent.contextInfo;
1264
+ }
1265
+ const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
1266
+ contextInfo.participant = (0, index_js_4.jidNormalizedUser)(participant);
1267
+ contextInfo.stanzaId = quoted.key.id;
1268
+ contextInfo.quotedMessage = quotedMsg;
1269
+ // if a participant is quoted, then it must be a group
1270
+ // hence, remoteJid of group must also be entered
1271
+ if (jid !== quoted.key.remoteJid) {
1272
+ contextInfo.remoteJid = quoted.key.remoteJid;
1273
+ }
1274
+ if (contextInfo && innerMessage[key]) {
1275
+ /* @ts-ignore */
722
1276
  innerMessage[key].contextInfo = contextInfo;
723
1277
  }
724
1278
  }
725
1279
  if (
726
1280
  // if we want to send a disappearing message
727
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
1281
+ !!options?.ephemeralExpiration &&
728
1282
  // and it's not a protocol message -- delete, toggle disappear message
729
1283
  key !== 'protocolMessage' &&
730
1284
  // already not converted to disappearing message
731
1285
  key !== 'ephemeralMessage' &&
732
- // newsletter not accept disappearing messages
733
- !(0, WABinary_1.isJidNewsletter)(jid)) {
1286
+ // newsletters don't support ephemeral messages
1287
+ !(0, index_js_4.isJidNewsletter)(jid)) {
1288
+ /* @ts-ignore */
734
1289
  innerMessage[key].contextInfo = {
735
1290
  ...(innerMessage[key].contextInfo || {}),
736
- expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
1291
+ expiration: options.ephemeralExpiration || index_js_2.WA_DEFAULT_EPHEMERAL
737
1292
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
738
1293
  };
739
1294
  }
740
- message = Types_1.WAProto.Message.fromObject(message);
1295
+ message = index_js_3.WAProto.Message.create(message);
741
1296
  const messageJSON = {
742
1297
  key: {
743
1298
  remoteJid: jid,
744
1299
  fromMe: true,
745
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageIDV2)(),
1300
+ id: options?.messageId || (0, generics_js_1.generateMessageIDV2)()
746
1301
  },
747
1302
  message: message,
748
1303
  messageTimestamp: timestamp,
749
1304
  messageStubParameters: [],
750
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
751
- status: Types_1.WAMessageStatus.PENDING
1305
+ participant: (0, index_js_4.isJidGroup)(jid) || (0, index_js_4.isJidStatusBroadcast)(jid) ? userJid : undefined, // TODO: Add support for LIDs
1306
+ status: index_js_3.WAMessageStatus.PENDING
752
1307
  };
753
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
1308
+ return index_js_3.WAProto.WebMessageInfo.fromObject(messageJSON);
754
1309
  };
755
1310
  exports.generateWAMessageFromContent = generateWAMessageFromContent;
756
1311
  const generateWAMessage = async (jid, content, options) => {
757
- var _a;
758
1312
  // ensure msg ID is with every log
759
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
760
- return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsletter)(jid), ...options }), options);
1313
+ options.logger = options?.logger?.child({ msgId: options.messageId });
1314
+ // Pass jid + newsletter flag to generateWAMessageContent (like wiley)
1315
+ const _isNewsletter = typeof jid === 'string' && jid.endsWith('@newsletter');
1316
+ return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: _isNewsletter, ...options, jid }), options);
761
1317
  };
762
1318
  exports.generateWAMessage = generateWAMessage;
763
1319
  /** Get the key to access the true type of content */
@@ -769,6 +1325,22 @@ const getContentType = (content) => {
769
1325
  }
770
1326
  };
771
1327
  exports.getContentType = getContentType;
1328
+ /**
1329
+ * Maps a message content type key to its MediaType string.
1330
+ * Handles ptvMessage → 'ptv', audioMessage ptt → 'ptt', etc.
1331
+ */
1332
+ const getMediaTypeFromContentType = (contentType, content) => {
1333
+ if (!contentType)
1334
+ return undefined;
1335
+ if (contentType === 'ptvMessage')
1336
+ return 'ptv';
1337
+ if (contentType === 'audioMessage' && content?.[contentType]?.ptt)
1338
+ return 'ptt';
1339
+ if (contentType === 'videoMessage' && content?.[contentType]?.gifPlayback)
1340
+ return 'gif';
1341
+ return contentType.replace('Message', '');
1342
+ };
1343
+ exports.getMediaTypeFromContentType = getMediaTypeFromContentType;
772
1344
  /**
773
1345
  * Normalizes ephemeral, view once messages to regular message content
774
1346
  * Eg. image messages in ephemeral messages, in view once messages etc.
@@ -789,29 +1361,15 @@ const normalizeMessageContent = (content) => {
789
1361
  }
790
1362
  return content;
791
1363
  function getFutureProofMessage(message) {
792
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
793
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
794
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
795
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
796
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
797
- || (message === null || message === void 0 ? void 0 : message.editedMessage)
798
- || (message === null || message === void 0 ? void 0 : message.groupMentionedMessage)
799
- || (message === null || message === void 0 ? void 0 : message.botInvokeMessage)
800
- || (message === null || message === void 0 ? void 0 : message.lottieStickerMessage)
801
- || (message === null || message === void 0 ? void 0 : message.eventCoverImage)
802
- || (message === null || message === void 0 ? void 0 : message.statusMentionMessage)
803
- || (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage)
804
- || (message === null || message === void 0 ? void 0 : message.associatedChildMessage)
805
- || (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage)
806
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
807
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
808
- || (message === null || message === void 0 ? void 0 : message.statusAddYours)
809
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
810
- || (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
811
- || (message === null || message === void 0 ? void 0 : message.botTaskMessage)
812
- || (message === null || message === void 0 ? void 0 : message.questionMessage)
813
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2)
814
- || (message === null || message === void 0 ? void 0 : message.botForwardedMessage));
1364
+ return (message?.ephemeralMessage ||
1365
+ message?.viewOnceMessage ||
1366
+ message?.documentWithCaptionMessage ||
1367
+ message?.viewOnceMessageV2 ||
1368
+ message?.viewOnceMessageV2Extension ||
1369
+ message?.editedMessage ||
1370
+ message?.associatedChildMessage ||
1371
+ message?.groupStatusMessage ||
1372
+ message?.groupStatusMessageV2);
815
1373
  }
816
1374
  };
817
1375
  exports.normalizeMessageContent = normalizeMessageContent;
@@ -820,7 +1378,6 @@ exports.normalizeMessageContent = normalizeMessageContent;
820
1378
  * Eg. extracts the inner message from a disappearing message/view once message
821
1379
  */
822
1380
  const extractMessageContent = (content) => {
823
- var _a, _b, _c, _d, _e, _f;
824
1381
  const extractFromTemplateMessage = (msg) => {
825
1382
  if (msg.imageMessage) {
826
1383
  return { imageMessage: msg.imageMessage };
@@ -836,24 +1393,22 @@ const extractMessageContent = (content) => {
836
1393
  }
837
1394
  else {
838
1395
  return {
839
- conversation: 'contentText' in msg
840
- ? msg.contentText
841
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
1396
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
842
1397
  };
843
1398
  }
844
1399
  };
845
1400
  content = (0, exports.normalizeMessageContent)(content);
846
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
1401
+ if (content?.buttonsMessage) {
847
1402
  return extractFromTemplateMessage(content.buttonsMessage);
848
1403
  }
849
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
850
- return extractFromTemplateMessage((_b = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _b === void 0 ? void 0 : _b.hydratedFourRowTemplate);
1404
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
1405
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
851
1406
  }
852
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
853
- return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedTemplate);
1407
+ if (content?.templateMessage?.hydratedTemplate) {
1408
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
854
1409
  }
855
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
856
- return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.fourRowTemplate);
1410
+ if (content?.templateMessage?.fourRowTemplate) {
1411
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
857
1412
  }
858
1413
  return content;
859
1414
  };
@@ -861,11 +1416,15 @@ exports.extractMessageContent = extractMessageContent;
861
1416
  /**
862
1417
  * Returns the device predicted by message ID
863
1418
  */
864
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' :
865
- /^3E.{20}$/.test(id) ? 'web' :
866
- /^(.{21}|.{32})$/.test(id) ? 'android' :
867
- /^(3F|.{18}$)/.test(id) ? 'desktop' :
868
- 'unknown';
1419
+ const getDevice = (id) => /^3A.{18}$/.test(id)
1420
+ ? 'ios'
1421
+ : /^3E.{20}$/.test(id)
1422
+ ? 'web'
1423
+ : /^(.{21}|.{32})$/.test(id)
1424
+ ? 'android'
1425
+ : /^(3F|.{18}$)/.test(id)
1426
+ ? 'desktop'
1427
+ : 'unknown';
869
1428
  exports.getDevice = getDevice;
870
1429
  /** Upserts a receipt in the message */
871
1430
  const updateMessageWithReceipt = (msg, receipt) => {
@@ -881,9 +1440,8 @@ const updateMessageWithReceipt = (msg, receipt) => {
881
1440
  exports.updateMessageWithReceipt = updateMessageWithReceipt;
882
1441
  /** Update the message with a new reaction */
883
1442
  const updateMessageWithReaction = (msg, reaction) => {
884
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
885
- const reactions = (msg.reactions || [])
886
- .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
1443
+ const authorID = (0, generics_js_1.getKeyAuthor)(reaction.key);
1444
+ const reactions = (msg.reactions || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.key) !== authorID);
887
1445
  reaction.text = reaction.text || '';
888
1446
  reactions.push(reaction);
889
1447
  msg.reactions = reactions;
@@ -891,16 +1449,22 @@ const updateMessageWithReaction = (msg, reaction) => {
891
1449
  exports.updateMessageWithReaction = updateMessageWithReaction;
892
1450
  /** Update the message with a new poll update */
893
1451
  const updateMessageWithPollUpdate = (msg, update) => {
894
- var _a, _b;
895
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
896
- const reactions = (msg.pollUpdates || [])
897
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
898
- if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
1452
+ const authorID = (0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey);
1453
+ const reactions = (msg.pollUpdates || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
1454
+ if (update.vote?.selectedOptions?.length) {
899
1455
  reactions.push(update);
900
1456
  }
901
1457
  msg.pollUpdates = reactions;
902
1458
  };
903
1459
  exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
1460
+ /** Update the message with a new event response */
1461
+ const updateMessageWithEventResponse = (msg, update) => {
1462
+ const authorID = (0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey);
1463
+ const responses = (msg.eventResponses || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID);
1464
+ responses.push(update);
1465
+ msg.eventResponses = responses;
1466
+ };
1467
+ exports.updateMessageWithEventResponse = updateMessageWithEventResponse;
904
1468
  /**
905
1469
  * Aggregates all poll updates in a poll.
906
1470
  * @param msg the poll creation message
@@ -908,10 +1472,12 @@ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
908
1472
  * @returns A list of options & their voters
909
1473
  */
910
1474
  function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
911
- var _a, _b, _c;
912
- const opts = ((_a = message === null || message === void 0 ? void 0 : message.pollCreationMessage) === null || _a === void 0 ? void 0 : _a.options) || ((_b = message === null || message === void 0 ? void 0 : message.pollCreationMessageV2) === null || _b === void 0 ? void 0 : _b.options) || ((_c = message === null || message === void 0 ? void 0 : message.pollCreationMessageV3) === null || _c === void 0 ? void 0 : _c.options) || [];
1475
+ const opts = message?.pollCreationMessage?.options ||
1476
+ message?.pollCreationMessageV2?.options ||
1477
+ message?.pollCreationMessageV3?.options ||
1478
+ [];
913
1479
  const voteHashMap = opts.reduce((acc, opt) => {
914
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
1480
+ const hash = (0, crypto_js_1.sha256)(Buffer.from(opt.optionName || '')).toString();
915
1481
  acc[hash] = {
916
1482
  name: opt.optionName || '',
917
1483
  voters: []
@@ -933,11 +1499,34 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
933
1499
  };
934
1500
  data = voteHashMap[hash];
935
1501
  }
936
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1502
+ voteHashMap[hash].voters.push((0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
937
1503
  }
938
1504
  }
939
1505
  return Object.values(voteHashMap);
940
1506
  }
1507
+ /**
1508
+ * Aggregates all event responses in an event message.
1509
+ * @param msg the event creation message
1510
+ * @param meId your jid
1511
+ * @returns A list of response types & their responders
1512
+ */
1513
+ function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1514
+ const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
1515
+ const responseMap = {};
1516
+ for (const type of responseTypes) {
1517
+ responseMap[type] = {
1518
+ response: type,
1519
+ responders: []
1520
+ };
1521
+ }
1522
+ for (const update of eventResponses || []) {
1523
+ const responseType = update.eventResponse || 'UNKNOWN';
1524
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1525
+ responseMap[responseType].responders.push((0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey, meId));
1526
+ }
1527
+ }
1528
+ return Object.values(responseMap);
1529
+ }
941
1530
  /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
942
1531
  const aggregateMessageKeysNotFromMe = (keys) => {
943
1532
  const keyMap = {};
@@ -962,20 +1551,15 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404];
962
1551
  * Downloads the given message. Throws an error if it's not a media message
963
1552
  */
964
1553
  const downloadMediaMessage = async (message, type, options, ctx) => {
965
- const result = await downloadMsg()
966
- .catch(async (error) => {
967
- var _a;
968
- if (ctx) {
969
- if (axios_1.default.isAxiosError(error)) {
970
- // check if the message requires a reupload
971
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
972
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
973
- // request reupload
974
- message = await ctx.reuploadRequest(message);
975
- const result = await downloadMsg();
976
- return result;
977
- }
978
- }
1554
+ const result = await downloadMsg().catch(async (error) => {
1555
+ if (ctx &&
1556
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1557
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1558
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1559
+ // request reupload
1560
+ message = await ctx.reuploadRequest(message);
1561
+ const result = await downloadMsg();
1562
+ return result;
979
1563
  }
980
1564
  throw error;
981
1565
  });
@@ -986,7 +1570,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
986
1570
  throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
987
1571
  }
988
1572
  const contentType = (0, exports.getContentType)(mContent);
989
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
1573
+ let mediaType = (0, exports.getMediaTypeFromContentType)(contentType, mContent);
990
1574
  const media = mContent[contentType];
991
1575
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
992
1576
  throw new boom_1.Boom(`"${contentType}" message is not a media message`);
@@ -1002,7 +1586,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
1002
1586
  else {
1003
1587
  download = media;
1004
1588
  }
1005
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
1589
+ const stream = await (0, messages_media_js_1.downloadContentFromMessage)(download, mediaType, options);
1006
1590
  if (type === 'buffer') {
1007
1591
  const bufferArray = [];
1008
1592
  for await (const chunk of stream) {
@@ -1017,33 +1601,148 @@ exports.downloadMediaMessage = downloadMediaMessage;
1017
1601
  /** Checks whether the given message is a media message; if it is returns the inner content */
1018
1602
  const assertMediaContent = (content) => {
1019
1603
  content = (0, exports.extractMessageContent)(content);
1020
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
1021
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
1022
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
1023
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
1024
- || (content === null || content === void 0 ? void 0 : content.stickerMessage);
1604
+ const mediaContent = content?.documentMessage ||
1605
+ content?.imageMessage ||
1606
+ content?.videoMessage ||
1607
+ content?.audioMessage ||
1608
+ content?.stickerMessage;
1025
1609
  if (!mediaContent) {
1026
1610
  throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
1027
1611
  }
1028
1612
  return mediaContent;
1029
1613
  };
1030
1614
  exports.assertMediaContent = assertMediaContent;
1031
-
1032
- const toJid = (id) => {
1033
- if (!id)
1034
- return '';
1035
- if (id.endsWith('@lid'))
1036
- return id.replace('@lid', '@s.whatsapp.net');
1037
- if (id.includes('@'))
1038
- return id;
1039
- return `${id}@s.whatsapp.net`;
1615
+ const patchMessageForMdIfRequired = (message) => {
1616
+ if (message?.buttonsMessage ||
1617
+ message?.templateMessage ||
1618
+ message?.listMessage ||
1619
+ message?.interactiveMessage?.nativeFlowMessage) {
1620
+ message = {
1621
+ viewOnceMessageV2Extension: {
1622
+ message: {
1623
+ messageContextInfo: {
1624
+ deviceListMetadataVersion: 2,
1625
+ deviceListMetadata: {}
1626
+ },
1627
+ ...message
1628
+ }
1629
+ }
1630
+ };
1631
+ }
1632
+ return message;
1040
1633
  };
1041
- exports.toJid = toJid;
1042
- const getSenderLid = (message) => {
1043
- const sender = message.key.participant || message.key.remoteJid;
1044
- const user = (0, WABinary_1.jidDecode)(sender)?.user || '';
1045
- const lid = (0, WABinary_1.jidEncode)(user, 'lid');
1046
- console.log('sender lid:', lid);
1047
- return { jid: sender, lid };
1634
+ exports.patchMessageForMdIfRequired = patchMessageForMdIfRequired;
1635
+ const prepareAlbumMessageContent = async (jid, albums, options) => {
1636
+ let mediaHandle;
1637
+ let mediaMsg;
1638
+ const message = [];
1639
+ const albumMsg = (0, exports.generateWAMessageFromContent)(jid, {
1640
+ albumMessage: {
1641
+ expectedImageCount: albums.filter(item => 'image' in item).length,
1642
+ expectedVideoCount: albums.filter(item => 'video' in item).length
1643
+ }
1644
+ }, options);
1645
+ await options.sock.relayMessage(jid, albumMsg.message, { messageId: albumMsg.key.id });
1646
+ for (const i in albums) {
1647
+ const media = albums[i];
1648
+ if ('image' in media) {
1649
+ mediaMsg = await (0, exports.generateWAMessage)(jid, { image: media.image, ...media, ...options }, {
1650
+ userJid: options.userJid,
1651
+ upload: async (encFilePath, opts) => {
1652
+ const up = await options.sock.waUploadToServer(encFilePath, { ...opts, newsletter: (0, index_js_4.isJidNewsletter)(jid) });
1653
+ mediaHandle = up.handle;
1654
+ return up;
1655
+ },
1656
+ ...options
1657
+ });
1658
+ }
1659
+ else if ('video' in media) {
1660
+ mediaMsg = await (0, exports.generateWAMessage)(jid, { video: media.video, ...media, ...options }, {
1661
+ userJid: options.userJid,
1662
+ upload: async (encFilePath, opts) => {
1663
+ const up = await options.sock.waUploadToServer(encFilePath, { ...opts, newsletter: (0, index_js_4.isJidNewsletter)(jid) });
1664
+ mediaHandle = up.handle;
1665
+ return up;
1666
+ },
1667
+ ...options
1668
+ });
1669
+ }
1670
+ if (mediaMsg) {
1671
+ mediaMsg.message.messageContextInfo = {
1672
+ messageSecret: (0, crypto_1.randomBytes)(32),
1673
+ messageAssociation: {
1674
+ associationType: 1,
1675
+ parentMessageKey: albumMsg.key
1676
+ }
1677
+ };
1678
+ }
1679
+ message.push(mediaMsg);
1680
+ }
1681
+ return message;
1682
+ };
1683
+ exports.prepareAlbumMessageContent = prepareAlbumMessageContent;
1684
+ /**
1685
+ * Ekstrak quoted message dari contextInfo pesan.
1686
+ * Return object yang sudah dinormalisasi, termasuk debug info LID/PN.
1687
+ *
1688
+ * @param {object} msg - WAMessage object dari event messages.upsert
1689
+ * @param {object} [options]
1690
+ * @param {boolean} [options.debug] - jika true, log info ke console
1691
+ * @returns {object|null} quoted message info atau null jika tidak ada
1692
+ */
1693
+ const getQuotedMsg = (msg, options = {}) => {
1694
+ const { debug = false } = options;
1695
+ const msgContent = (0, exports.normalizeMessageContent)(msg?.message);
1696
+ if (!msgContent)
1697
+ return null;
1698
+ const msgType = (0, exports.getContentType)(msgContent);
1699
+ if (!msgType)
1700
+ return null;
1701
+ const innerMsg = msgContent[msgType];
1702
+ if (!innerMsg)
1703
+ return null;
1704
+ const contextInfo = innerMsg.contextInfo;
1705
+ if (!contextInfo?.stanzaId || !contextInfo?.quotedMessage)
1706
+ return null;
1707
+ // Normalisasi participant (sender quoted message)
1708
+ const participant = contextInfo.participant || msg.key?.participant || msg.key?.remoteJid || '';
1709
+ // Normalisasi mentionedJid di quoted message
1710
+ const quotedMsgContent = (0, exports.normalizeMessageContent)(contextInfo.quotedMessage);
1711
+ const quotedMsgType = (0, exports.getContentType)(quotedMsgContent);
1712
+ const quotedInnerMsg = quotedMsgType ? quotedMsgContent?.[quotedMsgType] : null;
1713
+ const quotedMentionedJid = quotedInnerMsg?.contextInfo?.mentionedJid || [];
1714
+ const quotedText = quotedInnerMsg?.text || quotedInnerMsg?.caption || quotedInnerMsg?.conversation || '';
1715
+ const result = {
1716
+ key: {
1717
+ id: contextInfo.stanzaId,
1718
+ remoteJid: contextInfo.remoteJid || msg.key?.remoteJid || '',
1719
+ participant: participant,
1720
+ fromMe: false
1721
+ },
1722
+ message: contextInfo.quotedMessage,
1723
+ participant,
1724
+ sender: participant,
1725
+ text: quotedText,
1726
+ type: quotedMsgType || '',
1727
+ mentionedJid: quotedMentionedJid,
1728
+ // Debug info
1729
+ _rawContextInfo: debug ? contextInfo : undefined
1730
+ };
1731
+ if (debug) {
1732
+ const hasLidInText = typeof quotedText === 'string' && /@\d{13,20}/.test(quotedText);
1733
+ const hasLidInMentioned = quotedMentionedJid.some(j => j?.endsWith('@lid'));
1734
+ const hasLidParticipant = participant?.endsWith('@lid');
1735
+ console.log('[getQuotedMsg DEBUG]', JSON.stringify({
1736
+ stanzaId: contextInfo.stanzaId,
1737
+ participant,
1738
+ participantIsLid: hasLidParticipant,
1739
+ quotedText,
1740
+ textHasLid: hasLidInText,
1741
+ mentionedJid: quotedMentionedJid,
1742
+ mentionedHasLid: hasLidInMentioned,
1743
+ quotedMsgType
1744
+ }, null, 2));
1745
+ }
1746
+ return result;
1048
1747
  };
1049
- exports.getSenderLid = getSenderLid;
1748
+ exports.getQuotedMsg = getQuotedMsg;