jagproject 26.3.23 → 26.3.26

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 (209) 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 +49 -35
  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 +1181 -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/bridge-runtime.d.ts +1 -0
  104. package/lib/Utils/bridge-runtime.js +14 -0
  105. package/lib/Utils/browser-utils.d.ts +4 -0
  106. package/lib/Utils/browser-utils.js +38 -29
  107. package/lib/Utils/business.d.ts +23 -0
  108. package/lib/Utils/business.js +54 -48
  109. package/lib/Utils/chat-utils.d.ts +70 -0
  110. package/lib/Utils/chat-utils.js +284 -189
  111. package/lib/Utils/crypto.d.ts +37 -0
  112. package/lib/Utils/crypto.js +16 -41
  113. package/lib/Utils/decode-wa-message.d.ts +48 -0
  114. package/lib/Utils/decode-wa-message.js +128 -48
  115. package/lib/Utils/event-buffer.d.ts +34 -0
  116. package/lib/Utils/event-buffer.js +124 -62
  117. package/lib/Utils/generics.d.ts +91 -0
  118. package/lib/Utils/generics.js +154 -138
  119. package/lib/Utils/history.d.ts +22 -0
  120. package/lib/Utils/history.js +77 -34
  121. package/lib/Utils/identity-change-handler.d.ts +37 -0
  122. package/lib/Utils/identity-change-handler.js +54 -0
  123. package/lib/Utils/index.d.ts +22 -0
  124. package/lib/Utils/index.js +32 -19
  125. package/lib/Utils/link-preview.d.ts +21 -0
  126. package/lib/Utils/link-preview.js +12 -17
  127. package/lib/Utils/logger.d.ts +13 -0
  128. package/lib/Utils/lt-hash.d.ts +8 -0
  129. package/lib/Utils/lt-hash.js +2 -43
  130. package/lib/Utils/make-mutex.d.ts +9 -0
  131. package/lib/Utils/make-mutex.js +21 -27
  132. package/lib/Utils/message-retry-manager.d.ts +110 -0
  133. package/lib/Utils/message-retry-manager.js +143 -45
  134. package/lib/Utils/messages-media.d.ts +130 -0
  135. package/lib/Utils/messages-media.js +429 -502
  136. package/lib/Utils/messages-newsletter.d.ts +84 -0
  137. package/lib/Utils/messages-newsletter.js +295 -0
  138. package/lib/Utils/messages.d.ts +92 -0
  139. package/lib/Utils/messages.js +1025 -674
  140. package/lib/Utils/noise-handler.d.ts +20 -0
  141. package/lib/Utils/noise-handler.js +145 -91
  142. package/lib/Utils/pre-key-manager.d.ts +28 -0
  143. package/lib/Utils/pre-key-manager.js +112 -0
  144. package/lib/Utils/process-message.d.ts +60 -0
  145. package/lib/Utils/process-message.js +316 -184
  146. package/lib/Utils/reporting-utils.d.ts +11 -0
  147. package/lib/Utils/reporting-utils.js +262 -0
  148. package/lib/Utils/resolve-jid.d.ts +43 -0
  149. package/lib/Utils/resolve-jid.js +95 -0
  150. package/lib/Utils/rust-bridge-shim.d.ts +22 -0
  151. package/lib/Utils/rust-bridge-shim.js +70 -0
  152. package/lib/Utils/serial-task-queue.js +29 -0
  153. package/lib/Utils/signal.d.ts +34 -0
  154. package/lib/Utils/signal.js +56 -39
  155. package/lib/Utils/streamToBuffer.js +17 -0
  156. package/lib/Utils/sync-action-utils.d.ts +19 -0
  157. package/lib/Utils/sync-action-utils.js +52 -0
  158. package/lib/Utils/tc-token-utils.d.ts +12 -0
  159. package/lib/Utils/tc-token-utils.js +20 -0
  160. package/lib/Utils/use-mongo-file-auth-state.js +71 -0
  161. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  162. package/lib/Utils/use-multi-file-auth-state.js +11 -12
  163. package/lib/Utils/use-single-file-auth-state.js +73 -0
  164. package/lib/Utils/validate-connection.d.ts +11 -0
  165. package/lib/Utils/validate-connection.js +59 -82
  166. package/lib/Utils/wileys-event-stream.js +1 -61
  167. package/lib/WABinary/constants.d.ts +28 -0
  168. package/lib/WABinary/decode.d.ts +7 -0
  169. package/lib/WABinary/decode.js +39 -4
  170. package/lib/WABinary/encode.d.ts +3 -0
  171. package/lib/WABinary/encode.js +17 -11
  172. package/lib/WABinary/generic-utils.d.ts +15 -0
  173. package/lib/WABinary/generic-utils.js +46 -18
  174. package/lib/WABinary/index.d.ts +6 -0
  175. package/lib/WABinary/index.js +9 -5
  176. package/lib/WABinary/jid-utils.d.ts +48 -0
  177. package/lib/WABinary/jid-utils.js +67 -37
  178. package/lib/WABinary/types.d.ts +19 -0
  179. package/lib/WABinary/types.js +34 -0
  180. package/lib/WAM/BinaryInfo.d.ts +9 -0
  181. package/lib/WAM/constants.d.ts +40 -0
  182. package/lib/WAM/constants.js +19183 -11678
  183. package/lib/WAM/encode.d.ts +3 -0
  184. package/lib/WAM/encode.js +15 -17
  185. package/lib/WAM/index.d.ts +4 -0
  186. package/lib/WAM/index.js +3 -3
  187. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  188. package/lib/WAUSync/Protocols/USyncContactProtocol.js +6 -6
  189. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  190. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +9 -9
  191. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  192. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +6 -6
  193. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  194. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -8
  195. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  196. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +18 -17
  197. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  198. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +11 -3
  199. package/lib/WAUSync/Protocols/index.d.ts +5 -0
  200. package/lib/WAUSync/Protocols/index.js +6 -4
  201. package/lib/WAUSync/USyncQuery.d.ts +29 -0
  202. package/lib/WAUSync/USyncQuery.js +38 -30
  203. package/lib/WAUSync/USyncUser.d.ts +13 -0
  204. package/lib/WAUSync/index.d.ts +4 -0
  205. package/lib/WAUSync/index.js +3 -3
  206. package/lib/index.d.ts +12 -0
  207. package/lib/index.js +3 -5
  208. package/package.json +7 -4
  209. 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,55 +718,37 @@ const generateWAMessageContent = async (message, options) => {
444
718
  }
445
719
  }
446
720
  }
447
- else if ('stickerPack' in message && !!message.stickerPack) {
448
- const { zip } = require('fflate');
721
+ else if ((0, exports.hasNonNullishProperty)(message, 'stickerPack')) {
722
+ const { zip } = _require('fflate');
449
723
  const { stickers, cover, name, publisher, packId, description } = message.stickerPack;
450
- const coverSource = cover || ((stickers[0] && (stickers[0].data || stickers[0].sticker)) || null);
451
- if (!Array.isArray(stickers)) {
452
- throw new boom_1.Boom('stickerPack.stickers must be an array', { statusCode: 400 });
453
- }
724
+ // ── Validasi jumlah sticker ───────────────────────────────────────────
454
725
  if (stickers.length > 60) {
455
726
  throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
456
727
  }
457
728
  if (stickers.length === 0) {
458
729
  throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
459
730
  }
460
- const stickerPackId = packId || (0, generics_1.generateMessageIDV2)();
461
- let sharpLib = null;
462
- let jimpLib = null;
463
- try {
464
- sharpLib = require('sharp');
465
- }
466
- catch (_sharpError) { }
467
- try {
468
- jimpLib = require('jimp');
469
- }
470
- catch (_jimpError) { }
471
- if (!sharpLib && !jimpLib) {
472
- throw new boom_1.Boom('No image processing library available (install sharp or jimp)', { statusCode: 400 });
473
- }
474
- const isWebPBuffer = (buf) => (buf.length >= 12
475
- && buf[0] === 0x52
476
- && buf[1] === 0x49
477
- && buf[2] === 0x46
478
- && buf[3] === 0x46
479
- && buf[8] === 0x57
480
- && buf[9] === 0x45
481
- && buf[10] === 0x42
482
- && buf[11] === 0x50);
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) ─────────────
483
741
  const isAnimatedWebP = (buf) => {
484
- if (!isWebPBuffer(buf)) {
742
+ if (!isWebPBuffer(buf))
485
743
  return false;
486
- }
487
744
  let offset = 12;
488
745
  while (offset < buf.length - 8) {
489
746
  const fourCC = buf.toString('ascii', offset, offset + 4);
490
747
  const chunkSize = buf.readUInt32LE(offset + 4);
491
748
  if (fourCC === 'VP8X') {
492
749
  const flagsOffset = offset + 8;
493
- if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02)) {
750
+ if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02))
494
751
  return true;
495
- }
496
752
  }
497
753
  else if (fourCC === 'ANIM' || fourCC === 'ANMF') {
498
754
  return true;
@@ -501,247 +757,81 @@ const generateWAMessageContent = async (message, options) => {
501
757
  }
502
758
  return false;
503
759
  };
504
- const getJimpBuffer = async (image, mime) => {
505
- if (typeof image.getBufferAsync === 'function') {
506
- return await image.getBufferAsync(mime);
507
- }
508
- return await new Promise((resolve, reject) => {
509
- image.getBuffer(mime, (err, result) => {
510
- if (err) {
511
- reject(err);
512
- }
513
- else {
514
- resolve(result);
515
- }
516
- });
517
- });
518
- };
519
- const { spawn } = require('child_process');
520
- const { promises: fsPromises } = require('fs');
521
- const { join } = require('path');
522
- const { tmpdir } = require('os');
523
- const isPngBuffer = (buf) => (buf.length >= 8
524
- && buf[0] === 0x89
525
- && buf[1] === 0x50
526
- && buf[2] === 0x4e
527
- && buf[3] === 0x47);
528
- const isJpegBuffer = (buf) => (buf.length >= 3
529
- && buf[0] === 0xff
530
- && buf[1] === 0xd8
531
- && buf[2] === 0xff);
532
- const isGifBuffer = (buf) => (buf.length >= 4 && buf.slice(0, 4).toString() === 'GIF8');
533
- const isWebmBuffer = (buf) => (buf.length >= 4
534
- && buf[0] === 0x1a
535
- && buf[1] === 0x45
536
- && buf[2] === 0xdf
537
- && buf[3] === 0xa3);
538
- const isMp4Buffer = (buf) => (buf.length >= 8
539
- && buf[4] === 0x66
540
- && buf[5] === 0x74
541
- && buf[6] === 0x79
542
- && buf[7] === 0x70);
543
- const looksLikeGzip = (buf) => (buf.length >= 2 && buf[0] === 0x1f && buf[1] === 0x8b);
544
- const inferSourceKind = (buffer, source, stickerItem) => {
545
- var _c, _d, _e, _f;
546
- if (isAnimatedWebP(buffer)) {
547
- return 'animated-webp';
548
- }
549
- if (isWebPBuffer(buffer)) {
550
- return 'webp';
551
- }
552
- if (isPngBuffer(buffer)) {
553
- return 'png';
554
- }
555
- if (isJpegBuffer(buffer)) {
556
- return 'jpg';
557
- }
558
- if (isGifBuffer(buffer)) {
559
- return 'gif';
560
- }
561
- if (isWebmBuffer(buffer)) {
562
- return 'webm';
563
- }
564
- if (isMp4Buffer(buffer)) {
565
- return 'mp4';
566
- }
567
- if (looksLikeGzip(buffer)) {
568
- return 'tgs';
569
- }
570
- const hint = String(((_c = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.format) !== null && _c !== void 0 ? _c : ((_d = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.mimetype) !== null && _d !== void 0 ? _d : ((_f = (_e = source) === null || _e === void 0 ? void 0 : _e.url) === null || _f === void 0 ? void 0 : _f.toString()))) || '').toLowerCase();
571
- if (hint.includes('webm')) {
572
- return 'webm';
573
- }
574
- if (hint.includes('mp4') || hint.includes('mov') || hint.includes('mkv') || hint.includes('avi')) {
575
- return 'mp4';
576
- }
577
- if (hint.includes('gif')) {
578
- return 'gif';
579
- }
580
- if (hint.includes('png')) {
581
- return 'png';
582
- }
583
- if (hint.includes('jpg') || hint.includes('jpeg')) {
584
- return 'jpg';
585
- }
586
- if (hint.includes('tgs') || hint.includes('lottie') || hint.includes('json')) {
587
- return 'tgs';
588
- }
589
- return 'unknown';
590
- };
591
- const convertStaticToWebp = async (buffer, label) => {
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;
592
767
  if (isWebPBuffer(buffer)) {
593
- return buffer;
594
- }
595
- if (sharpLib) {
596
- return await sharpLib(buffer)
597
- .resize(512, 512, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
598
- .webp({ quality: 80, lossless: false })
599
- .toBuffer();
600
- }
601
- if (jimpLib) {
602
- const JimpCtor = jimpLib.Jimp || jimpLib.default || jimpLib;
603
- const image = await JimpCtor.read(buffer);
604
- image.contain(512, 512);
605
- return await getJimpBuffer(image, 'image/webp');
606
- }
607
- throw new boom_1.Boom(`No image processing library available for converting ${label} to WebP`, { statusCode: 400 });
608
- };
609
- const runFfmpegToWebp = async (inputBuffer, inputExt, animated, label) => {
610
- const baseName = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
611
- const inputPath = join(tmpdir(), `sticker-pack-${baseName}.${inputExt || 'bin'}`);
612
- const outputPath = join(tmpdir(), `sticker-pack-${baseName}.webp`);
613
- await fsPromises.writeFile(inputPath, inputBuffer);
614
- const args = animated
615
- ? [
616
- '-y',
617
- '-i', inputPath,
618
- '-vf', 'fps=12,scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
619
- '-loop', '0',
620
- '-an',
621
- '-vsync', '0',
622
- '-s', '512:512',
623
- '-vcodec', 'libwebp_anim',
624
- '-lossless', '0',
625
- '-compression_level', '6',
626
- '-q:v', '55',
627
- outputPath,
628
- ]
629
- : [
630
- '-y',
631
- '-i', inputPath,
632
- '-vf', 'scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
633
- '-frames:v', '1',
634
- '-vcodec', 'libwebp',
635
- '-lossless', '0',
636
- '-compression_level', '6',
637
- '-q:v', '70',
638
- outputPath,
639
- ];
640
- await new Promise((resolve, reject) => {
641
- const ff = spawn('ffmpeg', args);
642
- let stderr = '';
643
- ff.stderr.on('data', (chunk) => {
644
- stderr += chunk.toString();
645
- });
646
- ff.on('error', (err) => reject(new boom_1.Boom(`ffmpeg not available for ${label}: ${err.message}`, { statusCode: 400 })));
647
- ff.on('close', (code) => {
648
- if (code === 0) {
649
- resolve(undefined);
650
- }
651
- else {
652
- reject(new boom_1.Boom(`ffmpeg failed while converting ${label} (code ${code})\n${stderr}`, { statusCode: 400 }));
653
- }
654
- });
655
- });
656
- try {
657
- return await fsPromises.readFile(outputPath);
768
+ webpBuffer = buffer;
769
+ isAnimated = isAnimatedWebP(buffer);
658
770
  }
659
- finally {
660
- await Promise.allSettled([
661
- fsPromises.unlink(inputPath),
662
- fsPromises.unlink(outputPath)
663
- ]);
771
+ else if ('sharp' in lib && lib.sharp) {
772
+ webpBuffer = await lib.sharp.default(buffer).webp().toBuffer();
664
773
  }
665
- };
666
- const toWebpBuffer = async (buffer, label, source, stickerItem) => {
667
- const sourceKind = inferSourceKind(buffer, source, stickerItem);
668
- if (sourceKind === 'animated-webp' || sourceKind === 'webp') {
669
- return buffer;
670
- }
671
- if (sourceKind === 'png' || sourceKind === 'jpg') {
672
- return await convertStaticToWebp(buffer, label);
673
- }
674
- if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4') {
675
- return await runFfmpegToWebp(buffer, sourceKind, true, label);
676
- }
677
- if (sourceKind === 'tgs') {
678
- throw new boom_1.Boom(`TGS/Lottie source for ${label} is not supported in this runtime`, { statusCode: 400 });
679
- }
680
- return await convertStaticToWebp(buffer, label);
681
- };
682
- const toStaticWebpCoverBuffer = async (buffer, label, source, stickerItem) => {
683
- const sourceKind = inferSourceKind(buffer, source, stickerItem);
684
- if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4' || sourceKind === 'animated-webp') {
685
- return await runFfmpegToWebp(buffer, sourceKind === 'animated-webp' ? 'webp' : sourceKind, false, label);
686
- }
687
- return await convertStaticToWebp(buffer, label);
688
- };
689
- const stickerData = {};
690
- const stickerMetadata = await Promise.all(stickers.map(async (stickerItem, index) => {
691
- const mediaSource = (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.data) || (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.sticker);
692
- if (!mediaSource) {
693
- throw new boom_1.Boom(`Sticker at index ${index} is missing data/sticker`, { statusCode: 400 });
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.');
694
777
  }
695
- const { stream } = await (0, messages_media_1.getStream)(mediaSource);
696
- const buffer = await (0, messages_media_1.toBuffer)(stream);
697
- const webpBuffer = await toWebpBuffer(buffer, `sticker at index ${index}`, mediaSource, stickerItem);
698
778
  if (webpBuffer.length > 1024 * 1024) {
699
- throw new boom_1.Boom(`Sticker at index ${index} exceeds the 1MB size limit`, { statusCode: 400 });
779
+ throw new boom_1.Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
700
780
  }
701
- const hash = (0, crypto_2.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
781
+ const hash = (0, crypto_js_1.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
702
782
  const fileName = `${hash}.webp`;
703
783
  stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
704
784
  return {
705
785
  fileName,
706
786
  mimetype: 'image/webp',
707
- isAnimated: isAnimatedWebP(webpBuffer),
708
- emojis: stickerItem.emojis || [],
709
- accessibilityLabel: stickerItem.accessibilityLabel || ''
787
+ isAnimated,
788
+ emojis: s.emojis || [],
789
+ accessibilityLabel: s.accessibilityLabel || ''
710
790
  };
711
- }));
791
+ });
792
+ const stickerMetadata = await Promise.all(stickerPromises);
793
+ // ── Step 2: proses cover & masukkan ke dalam ZIP ──────────────────────
712
794
  const trayIconFileName = `${stickerPackId}.webp`;
713
- if (!coverSource) {
714
- throw new boom_1.Boom('stickerPack.cover is required when no valid sticker media is available', { statusCode: 400 });
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();
802
+ }
803
+ else {
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.');
715
806
  }
716
- const { stream: coverStream } = await (0, messages_media_1.getStream)(coverSource);
717
- const coverBuffer = await (0, messages_media_1.toBuffer)(coverStream);
718
- const coverWebpBuffer = await toStaticWebpCoverBuffer(coverBuffer, 'cover', coverSource, stickers[0]);
719
807
  stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
808
+ // ── Step 3: buat ZIP buffer ───────────────────────────────────────────
720
809
  const zipBuffer = await new Promise((resolve, reject) => {
721
810
  zip(stickerData, (err, data) => {
722
- if (err) {
811
+ if (err)
723
812
  reject(err);
724
- }
725
- else {
813
+ else
726
814
  resolve(Buffer.from(data));
727
- }
728
815
  });
729
816
  });
730
- const stickerPackUpload = await (0, messages_media_1.encryptedStream)(zipBuffer, 'sticker-pack', {
817
+ // ── Step 4: encrypt ZIP (generate random mediaKey) ────────────────────
818
+ const stickerPackUpload = await (0, messages_media_js_1.encryptedStream)(zipBuffer, 'sticker-pack', {
731
819
  logger: options.logger,
732
820
  opts: options.options
733
821
  });
822
+ // ── Step 5: upload ZIP ────────────────────────────────────────────────
734
823
  const stickerPackUploadResult = await options.upload(stickerPackUpload.encWriteStream, {
735
824
  fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
736
825
  mediaType: 'sticker-pack',
737
826
  timeoutMs: options.mediaUploadTimeoutMs
738
827
  });
828
+ // ── Step 6: build stickerPackMessage ──────────────────────────────────
739
829
  m.stickerPackMessage = {
740
830
  name,
741
831
  publisher,
742
832
  stickerPackId,
743
833
  packDescription: description,
744
- stickerPackOrigin: WAProto_1.proto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
834
+ stickerPackOrigin: index_js_3.WAProto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
745
835
  stickerPackSize: zipBuffer.length,
746
836
  stickers: stickerMetadata,
747
837
  fileSha256: stickerPackUpload.fileSha256,
@@ -749,212 +839,219 @@ const generateWAMessageContent = async (message, options) => {
749
839
  mediaKey: stickerPackUpload.mediaKey,
750
840
  directPath: stickerPackUploadResult.directPath,
751
841
  fileLength: stickerPackUpload.fileLength,
752
- mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
842
+ mediaKeyTimestamp: (0, generics_js_1.unixTimestampSeconds)(),
753
843
  trayIconFileName
754
844
  };
845
+ // ── Step 7: generate & upload thumbnail (pakai mediaKey yang sama) ────
755
846
  try {
756
847
  let thumbnailBuffer;
757
- if (sharpLib) {
758
- thumbnailBuffer = await sharpLib(coverWebpBuffer).resize(252, 252).jpeg().toBuffer();
848
+ if ('sharp' in lib && lib.sharp) {
849
+ thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
759
850
  }
760
- else if (jimpLib) {
761
- const JimpCtor = jimpLib.Jimp || jimpLib.default || jimpLib;
762
- const image = await JimpCtor.read(coverWebpBuffer);
763
- thumbnailBuffer = await getJimpBuffer(image.resize({ w: 252, h: 252 }), 'image/jpeg');
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');
764
854
  }
765
- if (thumbnailBuffer && thumbnailBuffer.length) {
766
- const thumbUpload = await (0, messages_media_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
767
- logger: options.logger,
768
- opts: options.options,
769
- mediaKey: stickerPackUpload.mediaKey
770
- });
771
- const thumbUploadResult = await options.upload(thumbUpload.encWriteStream, {
772
- fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
773
- mediaType: 'thumbnail-sticker-pack',
774
- timeoutMs: options.mediaUploadTimeoutMs
775
- });
776
- Object.assign(m.stickerPackMessage, {
777
- thumbnailDirectPath: thumbUploadResult.directPath,
778
- thumbnailSha256: thumbUpload.fileSha256,
779
- thumbnailEncSha256: thumbUpload.fileEncSha256,
780
- thumbnailHeight: 252,
781
- thumbnailWidth: 252,
782
- imageDataHash: (0, crypto_2.sha256)(thumbnailBuffer).toString('base64')
783
- });
855
+ else {
856
+ throw new Error('No image processing library available for thumbnail generation');
784
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
+ });
785
879
  }
786
- catch (error) {
787
- var _r, _s;
788
- (_s = (_r = options.logger) === null || _r === void 0 ? void 0 : _r.warn) === null || _s === void 0 ? void 0 : _s.call(_r, { err: error }, 'sticker pack thumbnail generation failed');
880
+ catch (e) {
881
+ options.logger?.warn?.(`Thumbnail generation failed: ${e}`);
789
882
  }
790
883
  m.stickerPackMessage.contextInfo = {
791
- ...((message.contextInfo) || {}),
792
- ...((message.mentions) ? { mentionedJid: message.mentions } : {})
884
+ ...(message.contextInfo || {}),
885
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
793
886
  };
794
887
  }
795
- else if ('event' in message) {
796
- m.messageContextInfo = {
797
- messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32),
798
- };
799
- m.eventMessage = { ...message.event };
800
- }
801
- else if ('inviteAdmin' in message) {
888
+ else if ((0, exports.hasNonNullishProperty)(message, 'adminInvite')) {
802
889
  m.newsletterAdminInviteMessage = {};
803
- m.newsletterAdminInviteMessage.inviteExpiration = message.inviteAdmin.inviteExpiration;
804
- m.newsletterAdminInviteMessage.caption = message.inviteAdmin.text;
805
- m.newsletterAdminInviteMessage.newsletterJid = message.inviteAdmin.jid;
806
- m.newsletterAdminInviteMessage.newsletterName = message.inviteAdmin.subject;
807
- m.newsletterAdminInviteMessage.jpegThumbnail = message.inviteAdmin.thumbnail;
808
- }
809
- else if ('requestPayment' in message) {
810
- const sticker = ((_c = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _c === void 0 ? void 0 : _c.sticker) ?
811
- 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)
812
- : null;
813
- let notes = {};
814
- if ((_e = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _e === void 0 ? void 0 : _e.sticker) {
815
- notes = {
816
- stickerMessage: {
817
- ...sticker === null || sticker === void 0 ? void 0 : sticker.stickerMessage,
818
- contextInfo: (_f = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _f === void 0 ? void 0 : _f.contextInfo
819
- }
820
- };
821
- }
822
- else if (message.requestPayment.note) {
823
- notes = {
824
- extendedTextMessage: {
825
- text: message.requestPayment.note,
826
- contextInfo: (_g = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _g === void 0 ? void 0 : _g.contextInfo,
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;
827
903
  }
828
- };
904
+ }
905
+ catch (_) { }
829
906
  }
830
- else {
831
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
832
- }
833
- m.requestPaymentMessage = Types_1.WAProto.Message.RequestPaymentMessage.fromObject({
834
- expiryTimestamp: message.requestPayment.expiry,
835
- amount1000: message.requestPayment.amount,
836
- currencyCodeIso4217: message.requestPayment.currency,
837
- requestFrom: message.requestPayment.from,
838
- noteMessage: { ...notes },
839
- background: (_h = message.requestPayment.background) !== null && _h !== void 0 ? _h : null,
840
- });
907
+ m.newsletterAdminInviteMessage.contextInfo = {
908
+ ...(message.contextInfo || {}),
909
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
910
+ };
841
911
  }
842
- else if ('sharePhoneNumber' in message) {
912
+ else if ((0, exports.hasNonNullishProperty)(message, 'sharePhoneNumber')) {
843
913
  m.protocolMessage = {
844
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
914
+ type: index_js_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
845
915
  };
846
916
  }
847
- else if ('requestPhoneNumber' in message) {
917
+ else if ((0, exports.hasNonNullishProperty)(message, 'requestPhoneNumber')) {
848
918
  m.requestPhoneNumberMessage = {};
849
919
  }
850
- else if ('album' in message) {
851
- const imageMessages = message.album.filter(item => 'image' in item);
852
- const videoMessages = message.album.filter(item => 'video' in item);
853
- m.albumMessage = WAProto_1.proto.Message.AlbumMessage.fromObject({
854
- expectedImageCount: imageMessages.length,
855
- expectedVideoCount: videoMessages.length,
856
- });
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 };
857
936
  }
858
937
  else {
859
938
  m = await (0, exports.prepareWAMessageMedia)(message, options);
860
939
  }
861
- 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) {
862
979
  const buttonsMessage = {
863
- 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 }))
864
981
  };
865
982
  if ('text' in message) {
866
983
  buttonsMessage.contentText = message.text;
867
- buttonsMessage.headerType = ButtonType.EMPTY;
984
+ buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType.EMPTY;
868
985
  }
869
986
  else {
870
987
  if ('caption' in message) {
871
988
  buttonsMessage.contentText = message.caption;
872
989
  }
873
990
  const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
874
- buttonsMessage.headerType = ButtonType[type];
991
+ buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType[type];
875
992
  Object.assign(buttonsMessage, m);
876
993
  }
877
- if ('title' in message && !!message.title) {
878
- buttonsMessage.text = message.title,
879
- buttonsMessage.headerType = ButtonType.TEXT;
880
- }
881
994
  if ('footer' in message && !!message.footer) {
882
995
  buttonsMessage.footerText = message.footer;
883
996
  }
884
- if ('contextInfo' in message && !!message.contextInfo) {
885
- buttonsMessage.contextInfo = message.contextInfo;
886
- }
887
- if ('mentions' in message && !!message.mentions) {
888
- 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;
889
1000
  }
1001
+ buttonsMessage.contextInfo = {
1002
+ ...(message.contextInfo || {}),
1003
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
1004
+ };
890
1005
  m = { buttonsMessage };
891
1006
  }
892
1007
  else if ('templateButtons' in message && !!message.templateButtons) {
893
- const msg = {
894
- hydratedButtons: message.hasOwnProperty("templateButtons") ? message.templateButtons : message.templateButtons
1008
+ const hydratedTemplate = {
1009
+ hydratedButtons: message.templateButtons
895
1010
  };
896
1011
  if ('text' in message) {
897
- msg.hydratedContentText = message.text;
1012
+ hydratedTemplate.hydratedContentText = message.text;
898
1013
  }
899
1014
  else {
900
1015
  if ('caption' in message) {
901
- msg.hydratedContentText = message.caption;
1016
+ hydratedTemplate.hydratedContentText = message.caption;
902
1017
  }
903
- Object.assign(msg, m);
1018
+ Object.assign(hydratedTemplate, m);
904
1019
  }
905
1020
  if ('footer' in message && !!message.footer) {
906
- msg.hydratedFooterText = message.footer;
1021
+ hydratedTemplate.hydratedFooterText = message.footer;
907
1022
  }
908
- m = {
909
- templateMessage: {
910
- fourRowTemplate: msg,
911
- hydratedTemplate: msg
912
- }
913
- };
914
- }
915
- if ('sections' in message && !!message.sections) {
916
- const listMessage = {
917
- sections: message.sections,
918
- buttonText: message.buttonText,
919
- title: message.title,
920
- footerText: message.footer,
921
- description: message.text,
922
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
1023
+ hydratedTemplate.contextInfo = {
1024
+ ...(message.contextInfo || {}),
1025
+ ...(message.mentions ? { mentionedJid: message.mentions } : {})
923
1026
  };
924
- m = { listMessage };
1027
+ m = { templateMessage: { fourRowTemplate: hydratedTemplate, hydratedTemplate } };
925
1028
  }
926
- if ('interactiveButtons' in message && !!message.interactiveButtons) {
1029
+ else if ('interactiveButtons' in message && !!message.interactiveButtons) {
927
1030
  const interactiveMessage = {
928
- nativeFlowMessage: Types_1.WAProto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
1031
+ nativeFlowMessage: index_js_1.proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
929
1032
  buttons: message.interactiveButtons,
930
1033
  })
931
1034
  };
932
1035
  if ('text' in message) {
933
- interactiveMessage.body = {
934
- text: message.text
935
- };
1036
+ interactiveMessage.body = { text: message.text };
936
1037
  }
937
1038
  else if ('caption' in message) {
938
- interactiveMessage.body = {
939
- text: message.caption
940
- };
1039
+ interactiveMessage.body = { text: message.caption };
941
1040
  interactiveMessage.header = {
942
1041
  title: message.title,
943
1042
  subtitle: message.subtitle,
944
- hasMediaAttachment: (_j = message === null || message === void 0 ? void 0 : message.media) !== null && _j !== void 0 ? _j : false,
1043
+ hasMediaAttachment: message?.media ?? false,
945
1044
  };
946
1045
  Object.assign(interactiveMessage.header, m);
947
1046
  }
948
1047
  if ('footer' in message && !!message.footer) {
949
- interactiveMessage.footer = {
950
- text: message.footer
951
- };
1048
+ interactiveMessage.footer = { text: message.footer };
952
1049
  }
953
1050
  if ('title' in message && !!message.title) {
954
1051
  interactiveMessage.header = {
955
1052
  title: message.title,
956
1053
  subtitle: message.subtitle,
957
- hasMediaAttachment: (_k = message === null || message === void 0 ? void 0 : message.media) !== null && _k !== void 0 ? _k : false,
1054
+ hasMediaAttachment: message?.media ?? false,
958
1055
  };
959
1056
  Object.assign(interactiveMessage.header, m);
960
1057
  }
@@ -966,39 +1063,33 @@ const generateWAMessageContent = async (message, options) => {
966
1063
  }
967
1064
  m = { interactiveMessage };
968
1065
  }
969
- if ('shop' in message && !!message.shop) {
1066
+ else if ('shop' in message && !!message.shop) {
970
1067
  const interactiveMessage = {
971
- shopStorefrontMessage: Types_1.WAProto.Message.InteractiveMessage.ShopMessage.fromObject({
1068
+ shopStorefrontMessage: index_js_1.proto.Message.InteractiveMessage.ShopMessage.fromObject({
972
1069
  surface: message.shop,
973
1070
  id: message.id
974
1071
  })
975
1072
  };
976
1073
  if ('text' in message) {
977
- interactiveMessage.body = {
978
- text: message.text
979
- };
1074
+ interactiveMessage.body = { text: message.text };
980
1075
  }
981
1076
  else if ('caption' in message) {
982
- interactiveMessage.body = {
983
- text: message.caption
984
- };
1077
+ interactiveMessage.body = { text: message.caption };
985
1078
  interactiveMessage.header = {
986
1079
  title: message.title,
987
1080
  subtitle: message.subtitle,
988
- hasMediaAttachment: (_l = message === null || message === void 0 ? void 0 : message.media) !== null && _l !== void 0 ? _l : false,
1081
+ hasMediaAttachment: message?.media ?? false,
989
1082
  };
990
1083
  Object.assign(interactiveMessage.header, m);
991
1084
  }
992
1085
  if ('footer' in message && !!message.footer) {
993
- interactiveMessage.footer = {
994
- text: message.footer
995
- };
1086
+ interactiveMessage.footer = { text: message.footer };
996
1087
  }
997
1088
  if ('title' in message && !!message.title) {
998
1089
  interactiveMessage.header = {
999
1090
  title: message.title,
1000
1091
  subtitle: message.subtitle,
1001
- hasMediaAttachment: (_m = message === null || message === void 0 ? void 0 : message.media) !== null && _m !== void 0 ? _m : false,
1092
+ hasMediaAttachment: message?.media ?? false,
1002
1093
  };
1003
1094
  Object.assign(interactiveMessage.header, m);
1004
1095
  }
@@ -1010,30 +1101,143 @@ const generateWAMessageContent = async (message, options) => {
1010
1101
  }
1011
1102
  m = { interactiveMessage };
1012
1103
  }
1013
- if ('viewOnce' in message && !!message.viewOnce) {
1014
- 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 };
1139
+ }
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 } };
1015
1195
  }
1016
- if ('mentions' in message && ((_o = message.mentions) === null || _o === void 0 ? void 0 : _o.length)) {
1017
- const [messageType] = Object.keys(m);
1018
- m[messageType].contextInfo = m[messageType] || {};
1019
- m[messageType].contextInfo.mentionedJid = message.mentions;
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
+ }
1020
1213
  }
1021
- if ('edit' in message) {
1214
+ if (hasOptionalProperty(message, 'edit')) {
1022
1215
  m = {
1023
1216
  protocolMessage: {
1024
1217
  key: message.edit,
1025
1218
  editedMessage: m,
1026
1219
  timestampMs: Date.now(),
1027
- type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
1220
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
1028
1221
  }
1029
1222
  };
1030
1223
  }
1031
- if ('contextInfo' in message && !!message.contextInfo) {
1032
- const [messageType] = Object.keys(m);
1033
- m[messageType] = m[messageType] || {};
1034
- 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
+ }
1035
1239
  }
1036
- return Types_1.WAProto.Message.fromObject(m);
1240
+ return index_js_3.WAProto.Message.create(m);
1037
1241
  };
1038
1242
  exports.generateWAMessageContent = generateWAMessageContent;
1039
1243
  const generateWAMessageFromContent = (jid, message, options) => {
@@ -1044,68 +1248,72 @@ const generateWAMessageFromContent = (jid, message, options) => {
1044
1248
  }
1045
1249
  const innerMessage = (0, exports.normalizeMessageContent)(message);
1046
1250
  const key = (0, exports.getContentType)(innerMessage);
1047
- const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
1251
+ const timestamp = (0, generics_js_1.unixTimestampSeconds)(options.timestamp);
1048
1252
  const { quoted, userJid } = options;
1049
- // only set quoted if isn't a newsletter message
1050
- if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
1051
- 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;
1052
1257
  let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
1053
1258
  const msgType = (0, exports.getContentType)(quotedMsg);
1054
1259
  // strip any redundant properties
1055
- if (quotedMsg) {
1056
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
1057
- const quotedContent = quotedMsg[msgType];
1058
- if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
1059
- delete quotedContent.contextInfo;
1060
- }
1061
- const contextInfo = innerMessage[key].contextInfo || {};
1062
- contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
1063
- contextInfo.stanzaId = quoted.key.id;
1064
- contextInfo.quotedMessage = quotedMsg;
1065
- // if a participant is quoted, then it must be a group
1066
- // hence, remoteJid of group must also be entered
1067
- if (jid !== quoted.key.remoteJid) {
1068
- contextInfo.remoteJid = quoted.key.remoteJid;
1069
- }
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 */
1070
1276
  innerMessage[key].contextInfo = contextInfo;
1071
1277
  }
1072
1278
  }
1073
1279
  if (
1074
1280
  // if we want to send a disappearing message
1075
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
1281
+ !!options?.ephemeralExpiration &&
1076
1282
  // and it's not a protocol message -- delete, toggle disappear message
1077
1283
  key !== 'protocolMessage' &&
1078
1284
  // already not converted to disappearing message
1079
1285
  key !== 'ephemeralMessage' &&
1080
- // newsletter not accept disappearing messages
1081
- !(0, WABinary_1.isJidNewsletter)(jid)) {
1286
+ // newsletters don't support ephemeral messages
1287
+ !(0, index_js_4.isJidNewsletter)(jid)) {
1288
+ /* @ts-ignore */
1082
1289
  innerMessage[key].contextInfo = {
1083
1290
  ...(innerMessage[key].contextInfo || {}),
1084
- expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
1291
+ expiration: options.ephemeralExpiration || index_js_2.WA_DEFAULT_EPHEMERAL
1085
1292
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
1086
1293
  };
1087
1294
  }
1088
- message = Types_1.WAProto.Message.fromObject(message);
1295
+ message = index_js_3.WAProto.Message.create(message);
1089
1296
  const messageJSON = {
1090
1297
  key: {
1091
1298
  remoteJid: jid,
1092
1299
  fromMe: true,
1093
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageIDV2)(),
1300
+ id: options?.messageId || (0, generics_js_1.generateMessageIDV2)()
1094
1301
  },
1095
1302
  message: message,
1096
1303
  messageTimestamp: timestamp,
1097
1304
  messageStubParameters: [],
1098
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
1099
- 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
1100
1307
  };
1101
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
1308
+ return index_js_3.WAProto.WebMessageInfo.fromObject(messageJSON);
1102
1309
  };
1103
1310
  exports.generateWAMessageFromContent = generateWAMessageFromContent;
1104
1311
  const generateWAMessage = async (jid, content, options) => {
1105
- var _a;
1106
1312
  // ensure msg ID is with every log
1107
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
1108
- 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);
1109
1317
  };
1110
1318
  exports.generateWAMessage = generateWAMessage;
1111
1319
  /** Get the key to access the true type of content */
@@ -1117,6 +1325,22 @@ const getContentType = (content) => {
1117
1325
  }
1118
1326
  };
1119
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;
1120
1344
  /**
1121
1345
  * Normalizes ephemeral, view once messages to regular message content
1122
1346
  * Eg. image messages in ephemeral messages, in view once messages etc.
@@ -1137,29 +1361,15 @@ const normalizeMessageContent = (content) => {
1137
1361
  }
1138
1362
  return content;
1139
1363
  function getFutureProofMessage(message) {
1140
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
1141
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
1142
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
1143
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
1144
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
1145
- || (message === null || message === void 0 ? void 0 : message.editedMessage)
1146
- || (message === null || message === void 0 ? void 0 : message.groupMentionedMessage)
1147
- || (message === null || message === void 0 ? void 0 : message.botInvokeMessage)
1148
- || (message === null || message === void 0 ? void 0 : message.lottieStickerMessage)
1149
- || (message === null || message === void 0 ? void 0 : message.eventCoverImage)
1150
- || (message === null || message === void 0 ? void 0 : message.statusMentionMessage)
1151
- || (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage)
1152
- || (message === null || message === void 0 ? void 0 : message.associatedChildMessage)
1153
- || (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage)
1154
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
1155
- || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
1156
- || (message === null || message === void 0 ? void 0 : message.statusAddYours)
1157
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
1158
- || (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
1159
- || (message === null || message === void 0 ? void 0 : message.botTaskMessage)
1160
- || (message === null || message === void 0 ? void 0 : message.questionMessage)
1161
- || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2)
1162
- || (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);
1163
1373
  }
1164
1374
  };
1165
1375
  exports.normalizeMessageContent = normalizeMessageContent;
@@ -1168,7 +1378,6 @@ exports.normalizeMessageContent = normalizeMessageContent;
1168
1378
  * Eg. extracts the inner message from a disappearing message/view once message
1169
1379
  */
1170
1380
  const extractMessageContent = (content) => {
1171
- var _a, _b, _c, _d, _e, _f;
1172
1381
  const extractFromTemplateMessage = (msg) => {
1173
1382
  if (msg.imageMessage) {
1174
1383
  return { imageMessage: msg.imageMessage };
@@ -1184,24 +1393,22 @@ const extractMessageContent = (content) => {
1184
1393
  }
1185
1394
  else {
1186
1395
  return {
1187
- conversation: 'contentText' in msg
1188
- ? msg.contentText
1189
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
1396
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
1190
1397
  };
1191
1398
  }
1192
1399
  };
1193
1400
  content = (0, exports.normalizeMessageContent)(content);
1194
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
1401
+ if (content?.buttonsMessage) {
1195
1402
  return extractFromTemplateMessage(content.buttonsMessage);
1196
1403
  }
1197
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
1198
- 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);
1199
1406
  }
1200
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
1201
- 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);
1202
1409
  }
1203
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
1204
- 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);
1205
1412
  }
1206
1413
  return content;
1207
1414
  };
@@ -1209,11 +1416,15 @@ exports.extractMessageContent = extractMessageContent;
1209
1416
  /**
1210
1417
  * Returns the device predicted by message ID
1211
1418
  */
1212
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' :
1213
- /^3E.{20}$/.test(id) ? 'web' :
1214
- /^(.{21}|.{32})$/.test(id) ? 'android' :
1215
- /^(3F|.{18}$)/.test(id) ? 'desktop' :
1216
- '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';
1217
1428
  exports.getDevice = getDevice;
1218
1429
  /** Upserts a receipt in the message */
1219
1430
  const updateMessageWithReceipt = (msg, receipt) => {
@@ -1229,9 +1440,8 @@ const updateMessageWithReceipt = (msg, receipt) => {
1229
1440
  exports.updateMessageWithReceipt = updateMessageWithReceipt;
1230
1441
  /** Update the message with a new reaction */
1231
1442
  const updateMessageWithReaction = (msg, reaction) => {
1232
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
1233
- const reactions = (msg.reactions || [])
1234
- .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);
1235
1445
  reaction.text = reaction.text || '';
1236
1446
  reactions.push(reaction);
1237
1447
  msg.reactions = reactions;
@@ -1239,16 +1449,22 @@ const updateMessageWithReaction = (msg, reaction) => {
1239
1449
  exports.updateMessageWithReaction = updateMessageWithReaction;
1240
1450
  /** Update the message with a new poll update */
1241
1451
  const updateMessageWithPollUpdate = (msg, update) => {
1242
- var _a, _b;
1243
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
1244
- const reactions = (msg.pollUpdates || [])
1245
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
1246
- 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) {
1247
1455
  reactions.push(update);
1248
1456
  }
1249
1457
  msg.pollUpdates = reactions;
1250
1458
  };
1251
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;
1252
1468
  /**
1253
1469
  * Aggregates all poll updates in a poll.
1254
1470
  * @param msg the poll creation message
@@ -1256,10 +1472,12 @@ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
1256
1472
  * @returns A list of options & their voters
1257
1473
  */
1258
1474
  function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1259
- var _a, _b, _c;
1260
- 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
+ [];
1261
1479
  const voteHashMap = opts.reduce((acc, opt) => {
1262
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
1480
+ const hash = (0, crypto_js_1.sha256)(Buffer.from(opt.optionName || '')).toString();
1263
1481
  acc[hash] = {
1264
1482
  name: opt.optionName || '',
1265
1483
  voters: []
@@ -1281,11 +1499,34 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1281
1499
  };
1282
1500
  data = voteHashMap[hash];
1283
1501
  }
1284
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1502
+ voteHashMap[hash].voters.push((0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1285
1503
  }
1286
1504
  }
1287
1505
  return Object.values(voteHashMap);
1288
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
+ }
1289
1530
  /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
1290
1531
  const aggregateMessageKeysNotFromMe = (keys) => {
1291
1532
  const keyMap = {};
@@ -1310,20 +1551,15 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404];
1310
1551
  * Downloads the given message. Throws an error if it's not a media message
1311
1552
  */
1312
1553
  const downloadMediaMessage = async (message, type, options, ctx) => {
1313
- const result = await downloadMsg()
1314
- .catch(async (error) => {
1315
- var _a;
1316
- if (ctx) {
1317
- if (axios_1.default.isAxiosError(error)) {
1318
- // check if the message requires a reupload
1319
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
1320
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1321
- // request reupload
1322
- message = await ctx.reuploadRequest(message);
1323
- const result = await downloadMsg();
1324
- return result;
1325
- }
1326
- }
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;
1327
1563
  }
1328
1564
  throw error;
1329
1565
  });
@@ -1334,7 +1570,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
1334
1570
  throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
1335
1571
  }
1336
1572
  const contentType = (0, exports.getContentType)(mContent);
1337
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
1573
+ let mediaType = (0, exports.getMediaTypeFromContentType)(contentType, mContent);
1338
1574
  const media = mContent[contentType];
1339
1575
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
1340
1576
  throw new boom_1.Boom(`"${contentType}" message is not a media message`);
@@ -1350,7 +1586,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
1350
1586
  else {
1351
1587
  download = media;
1352
1588
  }
1353
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
1589
+ const stream = await (0, messages_media_js_1.downloadContentFromMessage)(download, mediaType, options);
1354
1590
  if (type === 'buffer') {
1355
1591
  const bufferArray = [];
1356
1592
  for await (const chunk of stream) {
@@ -1365,33 +1601,148 @@ exports.downloadMediaMessage = downloadMediaMessage;
1365
1601
  /** Checks whether the given message is a media message; if it is returns the inner content */
1366
1602
  const assertMediaContent = (content) => {
1367
1603
  content = (0, exports.extractMessageContent)(content);
1368
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
1369
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
1370
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
1371
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
1372
- || (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;
1373
1609
  if (!mediaContent) {
1374
1610
  throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
1375
1611
  }
1376
1612
  return mediaContent;
1377
1613
  };
1378
1614
  exports.assertMediaContent = assertMediaContent;
1379
-
1380
- const toJid = (id) => {
1381
- if (!id)
1382
- return '';
1383
- if (id.endsWith('@lid'))
1384
- return id.replace('@lid', '@s.whatsapp.net');
1385
- if (id.includes('@'))
1386
- return id;
1387
- 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;
1388
1633
  };
1389
- exports.toJid = toJid;
1390
- const getSenderLid = (message) => {
1391
- const sender = message.key.participant || message.key.remoteJid;
1392
- const user = (0, WABinary_1.jidDecode)(sender)?.user || '';
1393
- const lid = (0, WABinary_1.jidEncode)(user, 'lid');
1394
- console.log('sender lid:', lid);
1395
- 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;
1396
1747
  };
1397
- exports.getSenderLid = getSenderLid;
1748
+ exports.getQuotedMsg = getQuotedMsg;