@alannxd/baileys 6.0.6 → 6.0.9

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 (220) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +341 -286
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.d.ts +79257 -0
  7. package/WAProto/index.js +205861 -60565
  8. package/engine-requirements.js +1 -1
  9. package/lib/Defaults/index.js +119 -136
  10. package/lib/Signal/Group/ciphertext-message.js +2 -5
  11. package/lib/Signal/Group/group-session-builder.js +7 -41
  12. package/lib/Signal/Group/group_cipher.js +37 -51
  13. package/lib/Signal/Group/index.js +12 -57
  14. package/lib/Signal/Group/keyhelper.js +7 -44
  15. package/lib/Signal/Group/sender-chain-key.js +7 -15
  16. package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
  17. package/lib/Signal/Group/sender-key-message.js +9 -12
  18. package/lib/Signal/Group/sender-key-name.js +2 -5
  19. package/lib/Signal/Group/sender-key-record.js +9 -21
  20. package/lib/Signal/Group/sender-key-state.js +27 -42
  21. package/lib/Signal/Group/sender-message-key.js +4 -7
  22. package/lib/Signal/libsignal.js +347 -90
  23. package/lib/Signal/lid-mapping.js +277 -0
  24. package/lib/Socket/Client/index.js +3 -19
  25. package/lib/Socket/Client/types.js +11 -0
  26. package/lib/Socket/Client/websocket.js +54 -0
  27. package/lib/Socket/business.js +162 -43
  28. package/lib/Socket/chats.js +627 -427
  29. package/lib/Socket/communities.js +90 -80
  30. package/lib/Socket/groups.js +154 -161
  31. package/lib/Socket/index.js +11 -10
  32. package/lib/Socket/luxu.js +315 -469
  33. package/lib/Socket/messages-recv.js +1421 -615
  34. package/lib/Socket/messages-send.js +1150 -799
  35. package/lib/Socket/mex.js +42 -0
  36. package/lib/Socket/newsletter.js +152 -204
  37. package/lib/Socket/socket.js +544 -313
  38. package/lib/Store/index.js +10 -10
  39. package/lib/Store/keyed-db.js +108 -0
  40. package/lib/Store/make-cache-manager-store.js +43 -41
  41. package/lib/Store/make-in-memory-store.js +112 -341
  42. package/lib/Store/make-ordered-dictionary.js +14 -20
  43. package/lib/Store/object-repository.js +11 -6
  44. package/lib/Types/Auth.js +2 -2
  45. package/lib/Types/Bussines.js +2 -0
  46. package/lib/Types/Call.js +2 -2
  47. package/lib/Types/Chat.js +8 -4
  48. package/lib/Types/Contact.js +2 -2
  49. package/lib/Types/Events.js +2 -2
  50. package/lib/Types/GroupMetadata.js +2 -2
  51. package/lib/Types/Label.js +3 -5
  52. package/lib/Types/LabelAssociation.js +3 -5
  53. package/lib/Types/Message.js +11 -9
  54. package/lib/Types/Mex.js +37 -0
  55. package/lib/Types/Product.js +2 -2
  56. package/lib/Types/Signal.js +2 -2
  57. package/lib/Types/Socket.js +3 -2
  58. package/lib/Types/State.js +56 -2
  59. package/lib/Types/USync.js +2 -2
  60. package/lib/Types/index.js +15 -31
  61. package/lib/Utils/auth-utils.js +239 -143
  62. package/lib/Utils/browser-utils.js +48 -0
  63. package/lib/Utils/business.js +66 -69
  64. package/lib/Utils/chat-utils.js +396 -253
  65. package/lib/Utils/companion-reg-client-utils.js +35 -0
  66. package/lib/Utils/crypto.js +57 -90
  67. package/lib/Utils/decode-wa-message.js +236 -84
  68. package/lib/Utils/event-buffer.js +185 -77
  69. package/lib/Utils/generics.js +189 -209
  70. package/lib/Utils/history.js +93 -55
  71. package/lib/Utils/identity-change-handler.js +50 -0
  72. package/lib/Utils/index.js +23 -33
  73. package/lib/Utils/link-preview.js +16 -24
  74. package/lib/Utils/logger.js +3 -7
  75. package/lib/Utils/lt-hash.js +3 -46
  76. package/lib/Utils/make-mutex.js +24 -34
  77. package/lib/Utils/message-composer.js +273 -0
  78. package/lib/Utils/message-retry-manager.js +265 -0
  79. package/lib/Utils/messages-media.js +451 -482
  80. package/lib/Utils/messages.js +795 -369
  81. package/lib/Utils/noise-handler.js +145 -99
  82. package/lib/Utils/offline-node-processor.js +40 -0
  83. package/lib/Utils/pre-key-manager.js +106 -0
  84. package/lib/Utils/process-message.js +459 -150
  85. package/lib/Utils/reporting-utils.js +258 -0
  86. package/lib/Utils/signal.js +120 -72
  87. package/lib/Utils/stanza-ack.js +38 -0
  88. package/lib/Utils/sync-action-utils.js +49 -0
  89. package/lib/Utils/tc-token-utils.js +163 -0
  90. package/lib/Utils/use-multi-file-auth-state.js +29 -27
  91. package/lib/Utils/validate-connection.js +73 -99
  92. package/lib/WABinary/constants.js +1281 -20
  93. package/lib/WABinary/decode.js +52 -42
  94. package/lib/WABinary/encode.js +110 -155
  95. package/lib/WABinary/generic-utils.js +55 -49
  96. package/lib/WABinary/index.js +6 -21
  97. package/lib/WABinary/jid-utils.js +76 -40
  98. package/lib/WABinary/types.js +2 -2
  99. package/lib/WAM/BinaryInfo.js +2 -5
  100. package/lib/WAM/constants.js +19071 -11568
  101. package/lib/WAM/encode.js +17 -22
  102. package/lib/WAM/index.js +4 -19
  103. package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
  104. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
  105. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
  106. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
  107. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  108. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
  109. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
  110. package/lib/WAUSync/Protocols/index.js +6 -20
  111. package/lib/WAUSync/USyncQuery.js +44 -35
  112. package/lib/WAUSync/USyncUser.js +10 -5
  113. package/lib/WAUSync/index.js +4 -19
  114. package/lib/index.js +13 -36
  115. package/package.json +85 -51
  116. package/WAProto/fix-import.js +0 -29
  117. package/lib/Defaults/baileys-version.json +0 -3
  118. package/lib/Defaults/index.d.ts +0 -53
  119. package/lib/Defaults/phonenumber-mcc.json +0 -223
  120. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  121. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  122. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  123. package/lib/Signal/Group/index.d.ts +0 -11
  124. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  125. package/lib/Signal/Group/queue-job.d.ts +0 -1
  126. package/lib/Signal/Group/queue-job.js +0 -57
  127. package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
  128. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
  129. package/lib/Signal/Group/sender-key-message.d.ts +0 -18
  130. package/lib/Signal/Group/sender-key-name.d.ts +0 -17
  131. package/lib/Signal/Group/sender-key-record.d.ts +0 -30
  132. package/lib/Signal/Group/sender-key-state.d.ts +0 -38
  133. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  134. package/lib/Signal/libsignal.d.ts +0 -3
  135. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  136. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  137. package/lib/Socket/Client/index.d.ts +0 -3
  138. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  139. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  140. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  141. package/lib/Socket/Client/web-socket-client.js +0 -62
  142. package/lib/Socket/business.d.ts +0 -171
  143. package/lib/Socket/chats.d.ts +0 -267
  144. package/lib/Socket/communities.d.ts +0 -180
  145. package/lib/Socket/groups.d.ts +0 -115
  146. package/lib/Socket/index.d.ts +0 -173
  147. package/lib/Socket/luxu.d.ts +0 -266
  148. package/lib/Socket/messages-recv.d.ts +0 -161
  149. package/lib/Socket/messages-send.d.ts +0 -183
  150. package/lib/Socket/newsletter.d.ts +0 -134
  151. package/lib/Socket/registration.d.ts +0 -267
  152. package/lib/Socket/registration.js +0 -166
  153. package/lib/Socket/socket.d.ts +0 -44
  154. package/lib/Socket/usync.d.ts +0 -36
  155. package/lib/Socket/usync.js +0 -70
  156. package/lib/Store/index.d.ts +0 -3
  157. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  158. package/lib/Store/make-in-memory-store.d.ts +0 -118
  159. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  160. package/lib/Store/object-repository.d.ts +0 -10
  161. package/lib/Types/Auth.d.ts +0 -110
  162. package/lib/Types/Call.d.ts +0 -13
  163. package/lib/Types/Chat.d.ts +0 -102
  164. package/lib/Types/Contact.d.ts +0 -19
  165. package/lib/Types/Events.d.ts +0 -157
  166. package/lib/Types/GroupMetadata.d.ts +0 -55
  167. package/lib/Types/Label.d.ts +0 -35
  168. package/lib/Types/LabelAssociation.d.ts +0 -29
  169. package/lib/Types/Message.d.ts +0 -273
  170. package/lib/Types/Newsletter.d.ts +0 -103
  171. package/lib/Types/Newsletter.js +0 -38
  172. package/lib/Types/Product.d.ts +0 -78
  173. package/lib/Types/Signal.d.ts +0 -57
  174. package/lib/Types/Socket.d.ts +0 -111
  175. package/lib/Types/State.d.ts +0 -27
  176. package/lib/Types/USync.d.ts +0 -25
  177. package/lib/Types/index.d.ts +0 -57
  178. package/lib/Utils/auth-utils.d.ts +0 -18
  179. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  180. package/lib/Utils/baileys-event-stream.js +0 -63
  181. package/lib/Utils/business.d.ts +0 -22
  182. package/lib/Utils/chat-utils.d.ts +0 -71
  183. package/lib/Utils/crypto.d.ts +0 -41
  184. package/lib/Utils/decode-wa-message.d.ts +0 -19
  185. package/lib/Utils/event-buffer.d.ts +0 -35
  186. package/lib/Utils/generics.d.ts +0 -92
  187. package/lib/Utils/history.d.ts +0 -15
  188. package/lib/Utils/index.d.ts +0 -17
  189. package/lib/Utils/link-preview.d.ts +0 -21
  190. package/lib/Utils/logger.d.ts +0 -4
  191. package/lib/Utils/lt-hash.d.ts +0 -12
  192. package/lib/Utils/make-mutex.d.ts +0 -7
  193. package/lib/Utils/messages-media.d.ts +0 -116
  194. package/lib/Utils/messages.d.ts +0 -77
  195. package/lib/Utils/noise-handler.d.ts +0 -21
  196. package/lib/Utils/process-message.d.ts +0 -41
  197. package/lib/Utils/signal.d.ts +0 -32
  198. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  199. package/lib/Utils/validate-connection.d.ts +0 -11
  200. package/lib/WABinary/constants.d.ts +0 -30
  201. package/lib/WABinary/decode.d.ts +0 -7
  202. package/lib/WABinary/encode.d.ts +0 -3
  203. package/lib/WABinary/generic-utils.d.ts +0 -17
  204. package/lib/WABinary/index.d.ts +0 -5
  205. package/lib/WABinary/jid-utils.d.ts +0 -31
  206. package/lib/WABinary/types.d.ts +0 -18
  207. package/lib/WAM/BinaryInfo.d.ts +0 -17
  208. package/lib/WAM/constants.d.ts +0 -38
  209. package/lib/WAM/encode.d.ts +0 -3
  210. package/lib/WAM/index.d.ts +0 -3
  211. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  212. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  213. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  214. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  215. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  216. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  217. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  218. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  219. package/lib/WAUSync/USyncUser.d.ts +0 -12
  220. package/lib/index.d.ts +0 -12
@@ -1,56 +1,177 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.getAggregateVotesInPollMessage = 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;
7
- const boom_1 = require("@hapi/boom");
8
- const axios_1 = __importDefault(require("axios"));
9
- const crypto_1 = require("crypto");
10
- const fs_1 = require("fs");
11
- const WAProto_1 = require("../../WAProto");
12
- const Defaults_1 = require("../Defaults");
13
- const Types_1 = require("../Types");
14
- const WABinary_1 = require("../WABinary");
15
- const crypto_2 = require("./crypto");
16
- const generics_1 = require("./generics");
17
- const messages_media_1 = require("./messages-media");
1
+ import { Boom } from '@hapi/boom';
2
+ import { randomUUID, randomBytes } from 'crypto';
3
+ import { promises as fs } from 'fs';
4
+ import {} from 'stream';
5
+ import { proto } from '../../WAProto/index.js';
6
+ import { CALL_AUDIO_PREFIX, CALL_VIDEO_PREFIX, MEDIA_KEYS, URL_REGEX, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
7
+ import { WAMessageStatus, WAProto } from '../Types/index.js';
8
+ import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary/index.js';
9
+ import { sha256 } from './crypto.js';
10
+ import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
11
+ import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData } from './messages-media.js';
12
+ import { shouldIncludeReportingToken } from './reporting-utils.js';
18
13
  const MIMETYPE_MAP = {
19
14
  image: 'image/jpeg',
20
15
  video: 'video/mp4',
21
16
  document: 'application/pdf',
22
17
  audio: 'audio/ogg; codecs=opus',
23
18
  sticker: 'image/webp',
24
- 'product-catalog-image': 'image/jpeg',
19
+ 'product-catalog-image': 'image/jpeg'
25
20
  };
26
21
  const MessageTypeProto = {
27
- 'image': Types_1.WAProto.Message.ImageMessage,
28
- 'video': Types_1.WAProto.Message.VideoMessage,
29
- 'audio': Types_1.WAProto.Message.AudioMessage,
30
- 'sticker': Types_1.WAProto.Message.StickerMessage,
31
- 'document': Types_1.WAProto.Message.DocumentMessage,
22
+ image: WAProto.Message.ImageMessage,
23
+ video: WAProto.Message.VideoMessage,
24
+ audio: WAProto.Message.AudioMessage,
25
+ sticker: WAProto.Message.StickerMessage,
26
+ document: WAProto.Message.DocumentMessage
32
27
  };
33
- const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
28
+ const ButtonType = proto.Message.ButtonsMessage.HeaderType;
29
+ const RICH_RESPONSE_CODE_KEYWORDS = new Set([
30
+ 'break',
31
+ 'case',
32
+ 'catch',
33
+ 'continue',
34
+ 'debugger',
35
+ 'default',
36
+ 'delete',
37
+ 'do',
38
+ 'else',
39
+ 'finally',
40
+ 'for',
41
+ 'function',
42
+ 'if',
43
+ 'in',
44
+ 'instanceof',
45
+ 'new',
46
+ 'return',
47
+ 'switch',
48
+ 'this',
49
+ 'throw',
50
+ 'try',
51
+ 'typeof',
52
+ 'var',
53
+ 'void',
54
+ 'while',
55
+ 'with',
56
+ 'true',
57
+ 'false',
58
+ 'null',
59
+ 'undefined',
60
+ 'NaN',
61
+ 'Infinity',
62
+ 'class',
63
+ 'const',
64
+ 'let',
65
+ 'super',
66
+ 'extends',
67
+ 'export',
68
+ 'import',
69
+ 'yield',
70
+ 'static',
71
+ 'constructor',
72
+ 'of',
73
+ 'async',
74
+ 'await',
75
+ 'get',
76
+ 'set',
77
+ 'implements',
78
+ 'interface',
79
+ 'package',
80
+ 'private',
81
+ 'protected',
82
+ 'public',
83
+ 'enum',
84
+ 'throws',
85
+ 'transient'
86
+ ])
87
+ const tokenizeCode = code => {
88
+ const tokens = []
89
+ let i = 0
90
+ const len = code.length
91
+ while (i < len) {
92
+ if (/\s/.test(code[i])) {
93
+ const start = i
94
+ while (i < len && /\s/.test(code[i])) i++
95
+ tokens.push({ content: code.slice(start, i), type: 'DEFAULT' })
96
+ continue
97
+ }
98
+ if (code[i] === '"' || code[i] === "'" || code[i] === '`') {
99
+ const start = i
100
+ const quote = code[i]
101
+ i++
102
+ while (i < len && code[i] !== quote) {
103
+ if (code[i] === '\\') i++
104
+ i++
105
+ }
106
+ i++
107
+ tokens.push({ content: code.slice(start, i), type: 'STR' })
108
+ continue
109
+ }
110
+ if (code[i] === '/' && i + 1 < len && code[i + 1] === '/') {
111
+ const start = i
112
+ while (i < len && code[i] !== '\n') i++
113
+ tokens.push({ content: code.slice(start, i), type: 'COMMENT' })
114
+ continue
115
+ }
116
+ if (code[i] === '/' && i + 1 < len && code[i + 1] === '*') {
117
+ const start = i
118
+ i += 2
119
+ while (i + 1 < len && !(code[i] === '*' && code[i + 1] === '/')) i++
120
+ i += 2
121
+ tokens.push({ content: code.slice(start, i), type: 'COMMENT' })
122
+ continue
123
+ }
124
+ if (/[0-9]/.test(code[i])) {
125
+ const start = i
126
+ while (i < len && /[0-9.]/.test(code[i])) i++
127
+ tokens.push({ content: code.slice(start, i), type: 'NUMBER' })
128
+ continue
129
+ }
130
+ if (/[a-zA-Z_$]/.test(code[i])) {
131
+ const start = i
132
+ while (i < len && /[a-zA-Z0-9_$]/.test(code[i])) i++
133
+ const word = code.slice(start, i)
134
+ if (RICH_RESPONSE_CODE_KEYWORDS.has(word)) {
135
+ tokens.push({ content: word, type: 'KEYWORD' })
136
+ } else {
137
+ let j = i
138
+ while (j < len && /\s/.test(code[j])) j++
139
+ tokens.push({ content: word, type: j < len && code[j] === '(' ? 'METHOD' : 'DEFAULT' })
140
+ }
141
+ continue
142
+ }
143
+ tokens.push({ content: code[i], type: 'DEFAULT' })
144
+ i++
145
+ }
146
+ const merged = []
147
+ for (const t of tokens) {
148
+ if (merged.length && merged[merged.length - 1].type === 'DEFAULT' && t.type === 'DEFAULT') {
149
+ merged[merged.length - 1].content += t.content
150
+ } else {
151
+ merged.push(t)
152
+ }
153
+ }
154
+ return merged
155
+ }
34
156
  /**
35
157
  * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
36
158
  * @param text eg. hello https://google.com
37
159
  * @returns the URL, eg. https://google.com
38
160
  */
39
- const extractUrlFromText = (text) => { var _a; return (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0]; };
40
- exports.extractUrlFromText = extractUrlFromText;
41
- const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
42
- const url = (0, exports.extractUrlFromText)(text);
161
+ export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
162
+ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
163
+ const url = extractUrlFromText(text);
43
164
  if (!!getUrlInfo && url) {
44
165
  try {
45
166
  const urlInfo = await getUrlInfo(url);
46
167
  return urlInfo;
47
168
  }
48
- catch (error) { // ignore if fails
49
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
169
+ catch (error) {
170
+ // ignore if fails
171
+ logger?.warn({ trace: error.stack }, 'url generation failed');
50
172
  }
51
173
  }
52
174
  };
53
- exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
54
175
  const assertColor = async (color) => {
55
176
  let assertedColor;
56
177
  if (typeof color === 'number') {
@@ -65,159 +186,150 @@ const assertColor = async (color) => {
65
186
  return assertedColor;
66
187
  }
67
188
  };
68
- const prepareWAMessageMedia = async (message, options) => {
189
+ export const prepareWAMessageMedia = async (message, options) => {
69
190
  const logger = options.logger;
70
191
  let mediaType;
71
- for (const key of Defaults_1.MEDIA_KEYS) {
192
+ for (const key of MEDIA_KEYS) {
72
193
  if (key in message) {
73
194
  mediaType = key;
74
195
  }
75
196
  }
76
197
  if (!mediaType) {
77
- throw new boom_1.Boom('Invalid media type', {
78
- statusCode: 400
79
- });
198
+ throw new Boom('Invalid media type', { statusCode: 400 });
80
199
  }
81
-
82
200
  const uploadData = {
83
201
  ...message,
84
- ...(message.annotations ? {
85
- annotations: message.annotations
86
- } : {
87
- annotations: [
88
- {
89
- polygonVertices: [
90
- {
91
- x: 60.71664810180664,
92
- y: -36.39784622192383
93
- },
94
- {
95
- x: -16.710189819335938,
96
- y: 49.263675689697266
97
- },
98
- {
99
- x: -56.585853576660156,
100
- y: 37.85963439941406
101
- },
102
- {
103
- x: 20.840980529785156,
104
- y: -47.80188751220703
105
- }
106
- ],
107
- newsletter: {
108
- newsletterJid: "120363420757607688@newsletter",
109
- serverMessageId: 0,
110
- newsletterName: "7eppeli - Information",
111
- contentType: "UPDATE",
112
- }
113
- }
114
- ]
115
- }),
116
202
  media: message[mediaType]
117
203
  };
118
204
  delete uploadData[mediaType];
205
+ // check if cacheable + generate cache key
119
206
  const cacheableKey = typeof uploadData.media === 'object' &&
120
- ('url' in uploadData.media) &&
207
+ 'url' in uploadData.media &&
121
208
  !!uploadData.media.url &&
122
- !!options.mediaCache && (
123
- mediaType + ':' + uploadData.media.url.toString());
124
-
209
+ !!options.mediaCache &&
210
+ mediaType + ':' + uploadData.media.url.toString();
125
211
  if (mediaType === 'document' && !uploadData.fileName) {
126
212
  uploadData.fileName = 'file';
127
213
  }
128
-
129
214
  if (!uploadData.mimetype) {
130
215
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
131
216
  }
132
-
133
217
  if (cacheableKey) {
134
- const mediaBuff = options.mediaCache.get(cacheableKey);
218
+ const mediaBuff = await options.mediaCache.get(cacheableKey);
135
219
  if (mediaBuff) {
136
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
137
- const obj = Types_1.WAProto.Message.decode(mediaBuff);
220
+ logger?.debug({ cacheableKey }, 'got media cache hit');
221
+ const obj = proto.Message.decode(mediaBuff);
138
222
  const key = `${mediaType}Message`;
139
223
  Object.assign(obj[key], { ...uploadData, media: undefined });
140
224
  return obj;
141
225
  }
142
226
  }
143
-
227
+ const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
228
+ if (isNewsletter) {
229
+ logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
230
+ const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
231
+ const fileSha256B64 = fileSha256.toString('base64');
232
+ const { mediaUrl, directPath } = await options.upload(filePath, {
233
+ fileEncSha256B64: fileSha256B64,
234
+ mediaType: mediaType,
235
+ timeoutMs: options.mediaUploadTimeoutMs
236
+ });
237
+ await fs.unlink(filePath);
238
+ const obj = WAProto.Message.fromObject({
239
+ // todo: add more support here
240
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
241
+ url: mediaUrl,
242
+ directPath,
243
+ fileSha256,
244
+ fileLength,
245
+ ...uploadData,
246
+ media: undefined
247
+ })
248
+ });
249
+ if (uploadData.ptv) {
250
+ obj.ptvMessage = obj.videoMessage;
251
+ delete obj.videoMessage;
252
+ }
253
+ if (obj.stickerMessage) {
254
+ obj.stickerMessage.stickerSentTs = Date.now();
255
+ }
256
+ if (cacheableKey) {
257
+ logger?.debug({ cacheableKey }, 'set cache');
258
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
259
+ }
260
+ return obj;
261
+ }
144
262
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
145
- const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
146
- (typeof uploadData['jpegThumbnail'] === 'undefined');
147
- const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
263
+ const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
264
+ const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
148
265
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
149
266
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
150
-
151
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
267
+ const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
152
268
  logger,
153
269
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
154
- opts: options.options,
155
- isPtt: uploadData.ptt,
156
- forceOpus: (mediaType === "audio" && uploadData.mimetype && uploadData.mimetype.includes('opus'))
270
+ opts: options.options
157
271
  });
158
-
159
- if (mediaType === 'audio' && opusConverted) {
160
- uploadData.mimetype = 'audio/ogg; codecs=opus';
161
- }
162
-
163
- const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
164
-
165
- const [{ mediaUrl, directPath, handle }] = await Promise.all([
272
+ const fileEncSha256B64 = fileEncSha256.toString('base64');
273
+ const [{ mediaUrl, directPath }] = await Promise.all([
166
274
  (async () => {
167
- const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
168
- logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
275
+ const result = await options.upload(encFilePath, {
276
+ fileEncSha256B64,
277
+ mediaType,
278
+ timeoutMs: options.mediaUploadTimeoutMs
279
+ });
280
+ logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
169
281
  return result;
170
282
  })(),
171
283
  (async () => {
172
284
  try {
173
285
  if (requiresThumbnailComputation) {
174
- const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
286
+ const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
175
287
  uploadData.jpegThumbnail = thumbnail;
176
288
  if (!uploadData.width && originalImageDimensions) {
177
289
  uploadData.width = originalImageDimensions.width;
178
290
  uploadData.height = originalImageDimensions.height;
179
- logger === null || logger === void 0 ? void 0 : logger.debug('set dimensions');
291
+ logger?.debug('set dimensions');
180
292
  }
181
- logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
293
+ logger?.debug('generated thumbnail');
182
294
  }
183
295
  if (requiresDurationComputation) {
184
- uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
185
- logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
296
+ uploadData.seconds = await getAudioDuration(originalFilePath);
297
+ logger?.debug('computed audio duration');
186
298
  }
187
299
  if (requiresWaveformProcessing) {
188
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
189
- logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
300
+ uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
301
+ logger?.debug('processed waveform');
190
302
  }
191
303
  if (requiresAudioBackground) {
192
304
  uploadData.backgroundArgb = await assertColor(options.backgroundColor);
193
- logger === null || logger === void 0 ? void 0 : logger.debug('computed backgroundColor audio status');
305
+ logger?.debug('computed backgroundColor audio status');
194
306
  }
195
307
  }
196
308
  catch (error) {
197
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
309
+ logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
198
310
  }
199
- })(),
200
- ])
201
- .finally(async () => {
202
- if (!Buffer.isBuffer(encWriteStream)) {
203
- encWriteStream.destroy();
311
+ })()
312
+ ]).finally(async () => {
313
+ try {
314
+ await fs.unlink(encFilePath);
315
+ if (originalFilePath) {
316
+ await fs.unlink(originalFilePath);
317
+ }
318
+ logger?.debug('removed tmp files');
204
319
  }
205
-
206
- if (didSaveToTmpPath && bodyPath) {
207
- await fs_1.promises.unlink(bodyPath);
208
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
320
+ catch (error) {
321
+ logger?.warn('failed to remove tmp file');
209
322
  }
210
323
  });
211
-
212
- const obj = Types_1.WAProto.Message.fromObject({
324
+ const obj = WAProto.Message.fromObject({
213
325
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
214
- url: handle ? undefined : mediaUrl,
326
+ url: mediaUrl,
215
327
  directPath,
216
- mediaKey: mediaKey,
217
- fileEncSha256: fileEncSha256,
328
+ mediaKey,
329
+ fileEncSha256,
218
330
  fileSha256,
219
331
  fileLength,
220
- mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
332
+ mediaKeyTimestamp: unixTimestampSeconds(),
221
333
  ...uploadData,
222
334
  media: undefined
223
335
  })
@@ -226,73 +338,308 @@ const prepareWAMessageMedia = async (message, options) => {
226
338
  obj.ptvMessage = obj.videoMessage;
227
339
  delete obj.videoMessage;
228
340
  }
229
-
230
341
  if (cacheableKey) {
231
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
232
- options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
342
+ logger?.debug({ cacheableKey }, 'set cache');
343
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
233
344
  }
234
-
235
345
  return obj;
236
346
  };
237
- exports.prepareWAMessageMedia = prepareWAMessageMedia;
238
- const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
347
+ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
239
348
  ephemeralExpiration = ephemeralExpiration || 0;
240
349
  const content = {
241
350
  ephemeralMessage: {
242
351
  message: {
243
352
  protocolMessage: {
244
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
353
+ type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
245
354
  ephemeralExpiration
246
355
  }
247
356
  }
248
357
  }
249
358
  };
250
- return Types_1.WAProto.Message.fromObject(content);
359
+ return WAProto.Message.fromObject(content);
251
360
  };
252
- exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
253
361
  /**
254
362
  * Generate forwarded message content like WA does
255
363
  * @param message the message to forward
256
364
  * @param options.forceForward will show the message as forwarded even if it is from you
257
365
  */
258
- const generateForwardMessageContent = (message, forceForward) => {
259
- var _a;
366
+ export const generateForwardMessageContent = (message, forceForward) => {
260
367
  let content = message.message;
261
368
  if (!content) {
262
- throw new boom_1.Boom('no content in message', { statusCode: 400 });
369
+ throw new Boom('no content in message', { statusCode: 400 });
263
370
  }
264
371
  // hacky copy
265
- content = (0, exports.normalizeMessageContent)(content);
266
- content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish());
372
+ content = normalizeMessageContent(content);
373
+ content = proto.Message.decode(proto.Message.encode(content).finish());
267
374
  let key = Object.keys(content)[0];
268
- let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
375
+ let score = content?.[key]?.contextInfo?.forwardingScore || 0;
269
376
  score += message.key.fromMe && !forceForward ? 0 : 1;
270
377
  if (key === 'conversation') {
271
378
  content.extendedTextMessage = { text: content[key] };
272
379
  delete content.conversation;
273
380
  key = 'extendedTextMessage';
274
381
  }
382
+ const key_ = content?.[key];
275
383
  if (score > 0) {
276
- content[key].contextInfo = { forwardingScore: score, isForwarded: true };
384
+ key_.contextInfo = { forwardingScore: score, isForwarded: true };
277
385
  }
278
386
  else {
279
- content[key].contextInfo = {};
387
+ key_.contextInfo = {};
280
388
  }
281
389
  return content;
282
390
  };
283
- exports.generateForwardMessageContent = generateForwardMessageContent;
284
- const generateWAMessageContent = async (message, options) => {
285
- var _a;
286
- var _b;
391
+ export const hasNonNullishProperty = (message, key) => {
392
+ return (typeof message === 'object' &&
393
+ message !== null &&
394
+ key in message &&
395
+ message[key] !== null &&
396
+ message[key] !== undefined);
397
+ };
398
+ function hasOptionalProperty(obj, key) {
399
+ return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
400
+ }
401
+ const applyContextInfoAndMentions = (interactiveMessage, message) => {
402
+ if ('contextInfo' in message && !!message.contextInfo) {
403
+ interactiveMessage.contextInfo = message.contextInfo
404
+ }
405
+ if ('mentions' in message && !!message.mentions) {
406
+ interactiveMessage.contextInfo = {
407
+ ...(interactiveMessage.contextInfo || {}),
408
+ mentionedJid: message.mentions
409
+ }
410
+ }
411
+ }
412
+ export const generateWAMessageContent = async (message, options) => {
413
+ var _a, _b;
287
414
  let m = {};
288
- if ('text' in message) {
415
+ if ('interactiveButtons' in message && !!message.interactiveButtons) {
416
+ const nativeFlow = proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
417
+ buttons: message.interactiveButtons,
418
+ messageParamsJson: message.messageParams ?? "{}"
419
+ });
420
+ let interactiveMessage = { nativeFlowMessage: nativeFlow };
421
+ if ('text' in message) {
422
+ interactiveMessage.body = { text: message.text };
423
+ } else if ('caption' in message) {
424
+ interactiveMessage.body = { text: message.caption };
425
+ }
426
+ if ('title' in message && !!message.title) {
427
+ interactiveMessage.header = {
428
+ title: message.title,
429
+ subtitle: message.subtitle || "",
430
+ hasMediaAttachment: false
431
+ };
432
+ let media = null;
433
+ if ('image' in message && !!message.image) {
434
+ media = await prepareWAMessageMedia({ image: message.image }, options);
435
+ interactiveMessage.header.imageMessage = media.imageMessage;
436
+ if (message.image.caption) {
437
+ interactiveMessage.header.imageMessage.caption = message.image.caption;
438
+ }
439
+ } else if ('video' in message && !!message.video) {
440
+ media = await prepareWAMessageMedia({ video: message.video }, options);
441
+ interactiveMessage.header.videoMessage = media.videoMessage;
442
+ if (message.video.caption) {
443
+ interactiveMessage.header.videoMessage.caption = message.video.caption;
444
+ }
445
+ } else if ('gif' in message && !!message.gif) {
446
+ media = await prepareWAMessageMedia({ video: message.gif }, options);
447
+ interactiveMessage.header.videoMessage = media.videoMessage;
448
+ interactiveMessage.header.videoMessage.gifPlayback = true;
449
+ if (message.gif.caption) {
450
+ interactiveMessage.header.videoMessage.caption = message.gif.caption;
451
+ }
452
+ } else if ('document' in message && !!message.document) {
453
+ media = await prepareWAMessageMedia({ document: message.document }, options);
454
+ interactiveMessage.header.documentMessage = media.documentMessage;
455
+ let docuR = interactiveMessage.header.documentMessage;
456
+ docuR.fileName = message.document.fileName || "Document";
457
+ docuR.mimetype = message.document.mimetype || docuR.mimetype;
458
+ if (message.document.caption) docuR.caption = message.document.caption;
459
+ if (message.document.jpegThumbnail) docuR.jpegThumbnail = message.document.jpegThumbnail;
460
+ } else if ('location' in message && !!message.location) {
461
+ let mLoc = message.location;
462
+ interactiveMessage.header.locationMessage = {
463
+ degreesLongitude: mLoc.longitude || 0,
464
+ degreesLatitude: mLoc.latitude || 0,
465
+ name: mLoc.name || null,
466
+ address: mLoc.address || null,
467
+ url: mLoc.url || null
468
+ };
469
+ media = true;
470
+ } else if ('thumbnail' in message && !!message.thumbnail) {
471
+ interactiveMessage.header.jpegThumbnail = message.thumbnail;
472
+ }
473
+ if (media || ('thumbnail' in message && !!message.thumbnail)) {
474
+ interactiveMessage.header.hasMediaAttachment = true;
475
+ }
476
+ }
477
+ if ('footer' in message && !!message.footer) {
478
+ interactiveMessage.footer = { text: message.footer };
479
+ }
480
+ applyContextInfoAndMentions(interactiveMessage, message);
481
+ m = { interactiveMessage };
482
+ }
483
+ else if ('buttons' in message && !!message.buttons) {
484
+ const buttonsMessage = {
485
+ buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
486
+ };
487
+ if ('text' in message) {
488
+ buttonsMessage.contentText = message.text;
489
+ buttonsMessage.headerType = ButtonType.EMPTY;
490
+ }
491
+ else {
492
+ if ('caption' in message) {
493
+ buttonsMessage.contentText = message.caption;
494
+ }
495
+ const contentType = getContentType(m);
496
+ const type = contentType.replace('Message', '').toUpperCase();
497
+ buttonsMessage.headerType = ButtonType[type];
498
+ Object.assign(buttonsMessage, m);
499
+ }
500
+ if ('footer' in message && !!message.footer) {
501
+ buttonsMessage.footerText = message.footer;
502
+ }
503
+ m = { buttonsMessage };
504
+ }
505
+ else if ('richResponse' in message) {
506
+ const {
507
+ text,
508
+ code,
509
+ language = 'javascript',
510
+ botJid = '867051314767696@bot',
511
+ table,
512
+ latex,
513
+ map,
514
+ imageUrl,
515
+ imageUrls,
516
+ responseId,
517
+ messageSecret: richSecret
518
+ } = message.richResponse
519
+ const sections = []
520
+ if (text) {
521
+ sections.push({
522
+ view_model: {
523
+ primitive: { text, __typename: 'GenAIMarkdownTextUXPrimitive' },
524
+ __typename: 'GenAISingleLayoutViewModel'
525
+ }
526
+ })
527
+ }
528
+ if (code) {
529
+ sections.push({
530
+ view_model: {
531
+ primitive: {
532
+ language,
533
+ code_blocks: tokenizeCode(String(code)),
534
+ __typename: 'GenAICodeUXPrimitive'
535
+ },
536
+ __typename: 'GenAISingleLayoutViewModel'
537
+ }
538
+ })
539
+ }
540
+ if (table && Array.isArray(table.rows)) {
541
+ sections.push({
542
+ view_model: {
543
+ primitive: {
544
+ rows: table.rows.map(row => ({
545
+ cells: Array.isArray(row) ? row.map(c => ({ text: String(c) })) : row.cells
546
+ })),
547
+ __typename: 'GenAITableUXPrimitive'
548
+ },
549
+ __typename: 'GenAISingleLayoutViewModel'
550
+ }
551
+ })
552
+ }
553
+ if (latex) {
554
+ const expressions = Array.isArray(latex)
555
+ ? latex.map(e => (typeof e === 'string' ? { expression: e } : e))
556
+ : [{ expression: String(latex) }]
557
+ sections.push({
558
+ view_model: {
559
+ primitive: { expressions, __typename: 'GenAILatexUXPrimitive' },
560
+ __typename: 'GenAISingleLayoutViewModel'
561
+ }
562
+ })
563
+ }
564
+ if (map) {
565
+ sections.push({
566
+ view_model: {
567
+ primitive: {
568
+ latitude: map.latitude,
569
+ longitude: map.longitude,
570
+ zoom: map.zoom,
571
+ title: map.title,
572
+ annotations: map.annotations || [],
573
+ __typename: 'GenAIMapUXPrimitive'
574
+ },
575
+ __typename: 'GenAISingleLayoutViewModel'
576
+ }
577
+ })
578
+ }
579
+ if (imageUrl) {
580
+ sections.push({
581
+ view_model: {
582
+ primitive: { url: imageUrl, __typename: 'GenAIInlineImageUXPrimitive' },
583
+ __typename: 'GenAISingleLayoutViewModel'
584
+ }
585
+ })
586
+ }
587
+ if (imageUrls && Array.isArray(imageUrls) && imageUrls.length > 0) {
588
+ sections.push({
589
+ view_model: {
590
+ primitive: {
591
+ urls: imageUrls.map(u => (typeof u === 'string' ? { url: u } : u)),
592
+ __typename: 'GenAIGridImageUXPrimitive'
593
+ },
594
+ __typename: 'GenAISingleLayoutViewModel'
595
+ }
596
+ })
597
+ }
598
+ if (!sections.length && !text) {
599
+ sections.push({
600
+ view_model: {
601
+ primitive: { text: '', __typename: 'GenAIMarkdownTextUXPrimitive' },
602
+ __typename: 'GenAISingleLayoutViewModel'
603
+ }
604
+ })
605
+ }
606
+ const unifiedData = {
607
+ response_id: responseId || randomUUID(),
608
+ sections
609
+ }
610
+ return proto.Message.fromObject({
611
+ messageContextInfo: {
612
+ deviceListMetadata: {},
613
+ deviceListMetadataVersion: 2,
614
+ messageSecret: richSecret || randomBytes(32)
615
+ },
616
+ botForwardedMessage: {
617
+ message: {
618
+ richResponseMessage: {
619
+ submessages: [],
620
+ messageType: 1,
621
+ unifiedResponse: { data: Buffer.from(JSON.stringify(unifiedData)) },
622
+ contextInfo: {
623
+ forwardingScore: 2,
624
+ isForwarded: true,
625
+ forwardedAiBotMessageInfo: { botJid },
626
+ botMessageSharingInfo: {
627
+ botEntryPointOrigin: 1,
628
+ forwardScore: 2
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+ })
635
+ }
636
+ else if (hasNonNullishProperty(message, 'text')) {
289
637
  const extContent = { text: message.text };
290
638
  let urlInfo = message.linkPreview;
291
639
  if (typeof urlInfo === 'undefined') {
292
- urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
640
+ urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
293
641
  }
294
642
  if (urlInfo) {
295
- extContent.canonicalUrl = urlInfo['canonical-url'];
296
643
  extContent.matchedText = urlInfo['matched-text'];
297
644
  extContent.jpegThumbnail = urlInfo.jpegThumbnail;
298
645
  extContent.description = urlInfo.description;
@@ -317,218 +664,274 @@ const generateWAMessageContent = async (message, options) => {
317
664
  }
318
665
  m.extendedTextMessage = extContent;
319
666
  }
320
- else if ('contacts' in message) {
667
+ else if (hasNonNullishProperty(message, 'contacts')) {
321
668
  const contactLen = message.contacts.contacts.length;
322
669
  if (!contactLen) {
323
- throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
670
+ throw new Boom('require atleast 1 contact', { statusCode: 400 });
324
671
  }
325
672
  if (contactLen === 1) {
326
- m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0]);
673
+ m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
327
674
  }
328
675
  else {
329
- m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts);
676
+ m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
330
677
  }
331
678
  }
332
- else if ('contact' in message) {
333
- m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contact);
679
+ else if (hasNonNullishProperty(message, 'location')) {
680
+ m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
334
681
  }
335
- else if ('location' in message) {
336
- m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
337
- }
338
- else if ('react' in message) {
682
+ else if (hasNonNullishProperty(message, 'react')) {
339
683
  if (!message.react.senderTimestampMs) {
340
684
  message.react.senderTimestampMs = Date.now();
341
685
  }
342
- m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
686
+ m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
343
687
  }
344
- else if ('delete' in message) {
688
+ else if (hasNonNullishProperty(message, 'delete')) {
345
689
  m.protocolMessage = {
346
690
  key: message.delete,
347
- type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
691
+ type: WAProto.Message.ProtocolMessage.Type.REVOKE
348
692
  };
349
693
  }
350
- else if ('forward' in message) {
351
- m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
694
+ else if (hasNonNullishProperty(message, 'forward')) {
695
+ m = generateForwardMessageContent(message.forward, message.force);
696
+ }
697
+ else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
698
+ const exp = typeof message.disappearingMessagesInChat === 'boolean'
699
+ ? message.disappearingMessagesInChat
700
+ ? WA_DEFAULT_EPHEMERAL
701
+ : 0
702
+ : message.disappearingMessagesInChat;
703
+ m = prepareDisappearingMessageSettingContent(exp);
704
+ }
705
+ else if (hasNonNullishProperty(message, 'groupInvite')) {
706
+ m.groupInviteMessage = {};
707
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
708
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
709
+ m.groupInviteMessage.caption = message.groupInvite.text;
710
+ m.groupInviteMessage.groupJid = message.groupInvite.jid;
711
+ m.groupInviteMessage.groupName = message.groupInvite.subject;
712
+ //TODO: use built-in interface and get disappearing mode info etc.
713
+ //TODO: cache / use store!?
714
+ if (options.getProfilePicUrl) {
715
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
716
+ if (pfpUrl) {
717
+ const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
718
+ if (resp.ok) {
719
+ const buf = Buffer.from(await resp.arrayBuffer());
720
+ m.groupInviteMessage.jpegThumbnail = buf;
721
+ }
722
+ }
723
+ }
352
724
  }
353
- else if ('disappearingMessagesInChat' in message) {
354
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
355
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
356
- message.disappearingMessagesInChat;
357
- m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
725
+ else if (hasNonNullishProperty(message, 'pin')) {
726
+ m.pinInChatMessage = {};
727
+ m.messageContextInfo = {};
728
+ m.pinInChatMessage.key = message.pin;
729
+ m.pinInChatMessage.type = message.type;
730
+ m.pinInChatMessage.senderTimestampMs = Date.now();
731
+ m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
358
732
  }
359
- else if ('buttonReply' in message) {
733
+ else if (hasNonNullishProperty(message, 'buttonReply')) {
360
734
  switch (message.type) {
361
735
  case 'template':
362
736
  m.templateButtonReplyMessage = {
363
737
  selectedDisplayText: message.buttonReply.displayText,
364
738
  selectedId: message.buttonReply.id,
365
- selectedIndex: message.buttonReply.index,
739
+ selectedIndex: message.buttonReply.index
366
740
  };
367
741
  break;
368
742
  case 'plain':
369
743
  m.buttonsResponseMessage = {
370
744
  selectedButtonId: message.buttonReply.id,
371
745
  selectedDisplayText: message.buttonReply.displayText,
372
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
746
+ type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
373
747
  };
374
748
  break;
375
749
  }
376
750
  }
377
- else if ('product' in message) {
378
- const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
379
- m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
751
+ else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
752
+ const { videoMessage } = await prepareWAMessageMedia({ video: message.ptv }, options);
753
+ m.ptvMessage = videoMessage;
754
+ }
755
+ else if (hasNonNullishProperty(message, 'product')) {
756
+ const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
757
+ m.productMessage = WAProto.Message.ProductMessage.create({
380
758
  ...message,
381
759
  product: {
382
760
  ...message.product,
383
- productImage: imageMessage,
761
+ productImage: imageMessage
384
762
  }
385
763
  });
386
764
  }
387
- else if ('listReply' in message) {
765
+ else if (hasNonNullishProperty(message, 'listReply')) {
388
766
  m.listResponseMessage = { ...message.listReply };
389
767
  }
390
- else if ('ptv' in message) {
391
- const { videoMessage } = await prepareWAMessageMedia(
392
- { video: message.ptv },
393
- options
394
- );
395
- m.ptvMessage = videoMessage;
768
+ else if (hasNonNullishProperty(message, 'event')) {
769
+ m.eventMessage = {};
770
+ const startTime = Math.floor(message.event.startDate.getTime() / 1000);
771
+ if (message.event.call && options.getCallLink) {
772
+ const token = await options.getCallLink(message.event.call, { startTime });
773
+ m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
774
+ }
775
+ m.messageContextInfo = {
776
+ // encKey
777
+ messageSecret: message.event.messageSecret || randomBytes(32)
778
+ };
779
+ m.eventMessage.name = message.event.name;
780
+ m.eventMessage.description = message.event.description;
781
+ m.eventMessage.startTime = startTime;
782
+ m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
783
+ m.eventMessage.isCanceled = message.event.isCancelled ?? false;
784
+ m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
785
+ m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
786
+ m.eventMessage.location = message.event.location;
396
787
  }
397
- else if ('poll' in message) {
398
- (_b = message.poll).selectableCount || (_b.selectableCount = 0);
788
+ else if (hasNonNullishProperty(message, 'poll')) {
789
+ (_a = message.poll).selectableCount || (_a.selectableCount = 0);
790
+ (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
399
791
  if (!Array.isArray(message.poll.values)) {
400
- throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
792
+ throw new Boom('Invalid poll values', { statusCode: 400 });
401
793
  }
402
- if (message.poll.selectableCount < 0
403
- || message.poll.selectableCount > message.poll.values.length) {
404
- throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, { statusCode: 400 });
794
+ if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
795
+ throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
796
+ statusCode: 400
797
+ });
405
798
  }
406
799
  m.messageContextInfo = {
407
800
  // encKey
408
- messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
801
+ messageSecret: message.poll.messageSecret || randomBytes(32)
409
802
  };
410
- m.pollCreationMessage = {
803
+ const pollCreationMessage = {
411
804
  name: message.poll.name,
412
805
  selectableOptionsCount: message.poll.selectableCount,
413
- options: message.poll.values.map(optionName => ({ optionName })),
414
- pollType: message.poll.type,
415
- correctAnswer: message.poll.answer
416
- };
417
- }
418
- else if ('sharePhoneNumber' in message) {
419
- m.protocolMessage = {
420
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
806
+ options: message.poll.values.map(optionName => ({ optionName }))
421
807
  };
422
- }
423
- else if ('requestPhoneNumber' in message) {
424
- m.requestPhoneNumberMessage = {};
425
- }
426
- else {
427
- m = await (0, exports.prepareWAMessageMedia)(message, options);
428
- }
429
- if ('buttons' in message && !!message.buttons) {
430
- const buttonsMessage = {
431
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
432
- };
433
- if ('text' in message) {
434
- buttonsMessage.contentText = message.text;
435
- buttonsMessage.headerType = ButtonType.EMPTY;
808
+ if (message.poll.toAnnouncementGroup) {
809
+ // poll v2 is for community announcement groups (single select and multiple)
810
+ m.pollCreationMessageV2 = pollCreationMessage;
436
811
  }
437
812
  else {
438
- if ('caption' in message) {
439
- buttonsMessage.contentText = message.caption;
813
+ if (message.poll.selectableCount === 1) {
814
+ //poll v3 is for single select polls
815
+ m.pollCreationMessageV3 = pollCreationMessage;
816
+ }
817
+ else {
818
+ // poll for multiple choice polls
819
+ m.pollCreationMessage = pollCreationMessage;
440
820
  }
441
- const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
442
- buttonsMessage.headerType = ButtonType[type];
443
- Object.assign(buttonsMessage, m);
444
- }
445
- if ('footer' in message && !!message.footer) {
446
- buttonsMessage.footerText = message.footer;
447
821
  }
448
- m = { buttonsMessage };
449
822
  }
450
- else if ('templateButtons' in message && !!message.templateButtons) {
451
- const msg = {
452
- hydratedButtons: message.templateButtons
823
+ else if (hasNonNullishProperty(message, 'album')) {
824
+ m.albumMessage = {
825
+ expectedImageCount: message.album.expectedImageCount,
826
+ expectedVideoCount: message.album.expectedVideoCount
453
827
  };
454
- if ('text' in message) {
455
- msg.hydratedContentText = message.text;
456
- }
457
- else {
458
- if ('caption' in message) {
459
- msg.hydratedContentText = message.caption;
460
- }
461
- Object.assign(msg, m);
462
- }
463
- if ('footer' in message && !!message.footer) {
464
- msg.hydratedFooterText = message.footer;
465
- }
466
- m = {
467
- templateMessage: {
468
- fourRowTemplate: msg,
469
- hydratedTemplate: msg
470
- }
828
+ }
829
+ else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
830
+ m.protocolMessage = {
831
+ type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
471
832
  };
472
833
  }
473
- if ('sections' in message && !!message.sections) {
474
- const listMessage = {
475
- sections: message.sections,
476
- buttonText: message.buttonText,
477
- title: message.title,
478
- footerText: message.footer,
479
- description: message.text,
480
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
834
+ else if (hasNonNullishProperty(message, 'requestPhoneNumber')) {
835
+ m.requestPhoneNumberMessage = {};
836
+ }
837
+ else if (hasNonNullishProperty(message, 'limitSharing')) {
838
+ m.protocolMessage = {
839
+ type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
840
+ limitSharing: {
841
+ sharingLimited: message.limitSharing === true,
842
+ trigger: 1,
843
+ limitSharingSettingTimestamp: Date.now(),
844
+ initiatedByMe: true
845
+ }
481
846
  };
482
- m = { listMessage };
483
847
  }
484
- if ('viewOnce' in message && !!message.viewOnce) {
848
+ else {
849
+ m = await prepareWAMessageMedia(message, options);
850
+ }
851
+ if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
485
852
  m = { viewOnceMessage: { message: m } };
486
853
  }
487
- if ('mentions' in message && ((_a = message.mentions) === null || _a === void 0 ? void 0 : _a.length)) {
488
- const [messageType] = Object.keys(m);
489
- m[messageType].contextInfo = m[messageType] || {};
490
- m[messageType].contextInfo.mentionedJid = message.mentions;
854
+ if ((hasOptionalProperty(message, 'mentions') && message.mentions?.length) ||
855
+ (hasOptionalProperty(message, 'mentionAll') && message.mentionAll)) {
856
+ const messageType = Object.keys(m)[0];
857
+ const key = m[messageType];
858
+ if (key && 'contextInfo' in key) {
859
+ key.contextInfo = key.contextInfo || {};
860
+ if (message.mentions?.length) {
861
+ key.contextInfo.mentionedJid = message.mentions;
862
+ }
863
+ if (message.mentionAll) {
864
+ key.contextInfo.nonJidMentions = 1;
865
+ }
866
+ }
867
+ else if (key) {
868
+ key.contextInfo = {
869
+ mentionedJid: message.mentions,
870
+ nonJidMentions: message.mentionAll ? 1 : 0
871
+ };
872
+ }
491
873
  }
492
- if ('edit' in message) {
874
+ if (hasOptionalProperty(message, 'edit')) {
493
875
  m = {
494
876
  protocolMessage: {
495
877
  key: message.edit,
496
878
  editedMessage: m,
497
879
  timestampMs: Date.now(),
498
- type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
880
+ type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
881
+ }
882
+ };
883
+ }
884
+ if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
885
+ const messageType = Object.keys(m)[0];
886
+ const key = m[messageType];
887
+ if ('contextInfo' in key && !!key.contextInfo) {
888
+ key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
889
+ }
890
+ else if (key) {
891
+ key.contextInfo = message.contextInfo;
892
+ }
893
+ }
894
+ if (hasOptionalProperty(message, 'albumParentKey') && !!message.albumParentKey) {
895
+ m.messageContextInfo = {
896
+ ...m.messageContextInfo,
897
+ messageAssociation: {
898
+ associationType: WAProto.MessageAssociation.AssociationType.MEDIA_ALBUM,
899
+ parentMessageKey: message.albumParentKey
499
900
  }
500
901
  };
501
902
  }
502
- if ('contextInfo' in message && !!message.contextInfo) {
503
- const [messageType] = Object.keys(m);
504
- m[messageType] = m[messageType] || {};
505
- m[messageType].contextInfo = message.contextInfo;
903
+ if (shouldIncludeReportingToken(m)) {
904
+ m.messageContextInfo = m.messageContextInfo || {};
905
+ if (!m.messageContextInfo.messageSecret) {
906
+ m.messageContextInfo.messageSecret = randomBytes(32);
907
+ }
506
908
  }
507
- return Types_1.WAProto.Message.fromObject(m);
909
+ return WAProto.Message.create(m);
508
910
  };
509
- exports.generateWAMessageContent = generateWAMessageContent;
510
- const generateWAMessageFromContent = (jid, message, options) => {
911
+ export const generateWAMessageFromContent = (jid, message, options) => {
511
912
  // set timestamp to now
512
913
  // if not specified
513
914
  if (!options.timestamp) {
514
915
  options.timestamp = new Date();
515
916
  }
516
- const innerMessage = (0, exports.normalizeMessageContent)(message);
517
- const key = (0, exports.getContentType)(innerMessage);
518
- const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
917
+ const innerMessage = normalizeMessageContent(message);
918
+ const key = getContentType(innerMessage);
919
+ const timestamp = unixTimestampSeconds(options.timestamp);
519
920
  const { quoted, userJid } = options;
520
- if (quoted && !(0, WABinary_1.isJidNewsLetter)(jid)) {
521
- const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
522
- let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
523
- const msgType = (0, exports.getContentType)(quotedMsg);
921
+ if (quoted && !isJidNewsletter(jid)) {
922
+ const participant = quoted.key.fromMe
923
+ ? userJid // TODO: Add support for LIDs
924
+ : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
925
+ let quotedMsg = normalizeMessageContent(quoted.message);
926
+ const msgType = getContentType(quotedMsg);
524
927
  // strip any redundant properties
525
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
928
+ quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
526
929
  const quotedContent = quotedMsg[msgType];
527
930
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
528
931
  delete quotedContent.contextInfo;
529
932
  }
530
- const contextInfo = innerMessage[key].contextInfo || {};
531
- contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
933
+ const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
934
+ contextInfo.participant = jidNormalizedUser(participant);
532
935
  contextInfo.stanzaId = quoted.key.id;
533
936
  contextInfo.quotedMessage = quotedMsg;
534
937
  // if a participant is quoted, then it must be a group
@@ -536,62 +939,63 @@ const generateWAMessageFromContent = (jid, message, options) => {
536
939
  if (jid !== quoted.key.remoteJid) {
537
940
  contextInfo.remoteJid = quoted.key.remoteJid;
538
941
  }
539
- innerMessage[key].contextInfo = contextInfo;
942
+ if (contextInfo && innerMessage[key]) {
943
+ /* @ts-ignore */
944
+ innerMessage[key].contextInfo = contextInfo;
945
+ }
540
946
  }
541
947
  if (
542
948
  // if we want to send a disappearing message
543
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
949
+ !!options?.ephemeralExpiration &&
544
950
  // and it's not a protocol message -- delete, toggle disappear message
545
951
  key !== 'protocolMessage' &&
546
952
  // already not converted to disappearing message
547
953
  key !== 'ephemeralMessage' &&
548
- // newsletter not accept disappearing messages
549
- !(0, WABinary_1.isJidNewsLetter)(jid)) {
954
+ // newsletters don't support ephemeral messages
955
+ !isJidNewsletter(jid)) {
956
+ /* @ts-ignore */
550
957
  innerMessage[key].contextInfo = {
551
958
  ...(innerMessage[key].contextInfo || {}),
552
- expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
959
+ expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
553
960
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
554
961
  };
555
962
  }
556
- message = Types_1.WAProto.Message.fromObject(message);
963
+ message = WAProto.Message.create(message);
557
964
  const messageJSON = {
558
965
  key: {
559
966
  remoteJid: jid,
560
967
  fromMe: true,
561
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
968
+ id: options?.messageId || generateMessageIDV2()
562
969
  },
563
970
  message: message,
564
971
  messageTimestamp: timestamp,
565
972
  messageStubParameters: [],
566
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
567
- status: Types_1.WAMessageStatus.PENDING
973
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
974
+ status: WAMessageStatus.PENDING
568
975
  };
569
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
976
+ return WAProto.WebMessageInfo.fromObject(messageJSON);
570
977
  };
571
- exports.generateWAMessageFromContent = generateWAMessageFromContent;
572
- const generateWAMessage = async (jid, content, options) => {
573
- var _a;
978
+ export const generateWAMessage = async (jid, content, options) => {
574
979
  // ensure msg ID is with every log
575
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
576
- return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsLetter)(jid), ...options }), options);
980
+ options.logger = options?.logger?.child({ msgId: options.messageId });
981
+ // Pass jid in the options to generateWAMessageContent
982
+ return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
577
983
  };
578
- exports.generateWAMessage = generateWAMessage;
579
984
  /** Get the key to access the true type of content */
580
- const getContentType = (content) => {
985
+ export const getContentType = (content) => {
581
986
  if (content) {
582
987
  const keys = Object.keys(content);
583
988
  const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
584
989
  return key;
585
990
  }
586
991
  };
587
- exports.getContentType = getContentType;
588
992
  /**
589
993
  * Normalizes ephemeral, view once messages to regular message content
590
994
  * Eg. image messages in ephemeral messages, in view once messages etc.
591
995
  * @param content
592
996
  * @returns
593
997
  */
594
- const normalizeMessageContent = (content) => {
998
+ export const normalizeMessageContent = (content) => {
595
999
  if (!content) {
596
1000
  return undefined;
597
1001
  }
@@ -605,21 +1009,22 @@ const normalizeMessageContent = (content) => {
605
1009
  }
606
1010
  return content;
607
1011
  function getFutureProofMessage(message) {
608
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
609
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
610
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
611
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
612
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
613
- || (message === null || message === void 0 ? void 0 : message.editedMessage));
1012
+ return (message?.ephemeralMessage ||
1013
+ message?.viewOnceMessage ||
1014
+ message?.documentWithCaptionMessage ||
1015
+ message?.viewOnceMessageV2 ||
1016
+ message?.viewOnceMessageV2Extension ||
1017
+ message?.editedMessage ||
1018
+ message?.associatedChildMessage ||
1019
+ message?.groupStatusMessage ||
1020
+ message?.groupStatusMessageV2);
614
1021
  }
615
1022
  };
616
- exports.normalizeMessageContent = normalizeMessageContent;
617
1023
  /**
618
1024
  * Extract the true message content from a message
619
1025
  * Eg. extracts the inner message from a disappearing message/view once message
620
1026
  */
621
- const extractMessageContent = (content) => {
622
- var _a, _b, _c, _d, _e, _f;
1027
+ export const extractMessageContent = (content) => {
623
1028
  const extractFromTemplateMessage = (msg) => {
624
1029
  if (msg.imageMessage) {
625
1030
  return { imageMessage: msg.imageMessage };
@@ -635,35 +1040,39 @@ const extractMessageContent = (content) => {
635
1040
  }
636
1041
  else {
637
1042
  return {
638
- conversation: 'contentText' in msg
639
- ? msg.contentText
640
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
1043
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
641
1044
  };
642
1045
  }
643
1046
  };
644
- content = (0, exports.normalizeMessageContent)(content);
645
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
1047
+ content = normalizeMessageContent(content);
1048
+ if (content?.buttonsMessage) {
646
1049
  return extractFromTemplateMessage(content.buttonsMessage);
647
1050
  }
648
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
649
- return extractFromTemplateMessage((_b = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _b === void 0 ? void 0 : _b.hydratedFourRowTemplate);
1051
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
1052
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
650
1053
  }
651
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
652
- return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedTemplate);
1054
+ if (content?.templateMessage?.hydratedTemplate) {
1055
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
653
1056
  }
654
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
655
- return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.fourRowTemplate);
1057
+ if (content?.templateMessage?.fourRowTemplate) {
1058
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
656
1059
  }
657
1060
  return content;
658
1061
  };
659
- exports.extractMessageContent = extractMessageContent;
660
1062
  /**
661
1063
  * Returns the device predicted by message ID
662
1064
  */
663
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' : /^3E.{20}$/.test(id) ? 'web' : /^(.{21}|.{32})$/.test(id) ? 'android' : /^.{18}$/.test(id) ? 'desktop' : 'unknown';
664
- exports.getDevice = getDevice;
1065
+ export const getDevice = (id) => /^3A.{18}$/.test(id)
1066
+ ? 'ios'
1067
+ : /^3E.{20}$/.test(id)
1068
+ ? 'web'
1069
+ : /^(.{21}|.{32})$/.test(id)
1070
+ ? 'android'
1071
+ : /^(3F|.{18}$)/.test(id)
1072
+ ? 'desktop'
1073
+ : 'wa bot';
665
1074
  /** Upserts a receipt in the message */
666
- const updateMessageWithReceipt = (msg, receipt) => {
1075
+ export const updateMessageWithReceipt = (msg, receipt) => {
667
1076
  msg.userReceipt = msg.userReceipt || [];
668
1077
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
669
1078
  if (recp) {
@@ -673,41 +1082,43 @@ const updateMessageWithReceipt = (msg, receipt) => {
673
1082
  msg.userReceipt.push(receipt);
674
1083
  }
675
1084
  };
676
- exports.updateMessageWithReceipt = updateMessageWithReceipt;
677
1085
  /** Update the message with a new reaction */
678
- const updateMessageWithReaction = (msg, reaction) => {
679
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
680
- const reactions = (msg.reactions || [])
681
- .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
682
- if (reaction.text) {
683
- reactions.push(reaction);
684
- }
1086
+ export const updateMessageWithReaction = (msg, reaction) => {
1087
+ const authorID = getKeyAuthor(reaction.key);
1088
+ const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
1089
+ reaction.text = reaction.text || '';
1090
+ reactions.push(reaction);
685
1091
  msg.reactions = reactions;
686
1092
  };
687
- exports.updateMessageWithReaction = updateMessageWithReaction;
688
1093
  /** Update the message with a new poll update */
689
- const updateMessageWithPollUpdate = (msg, update) => {
690
- var _a, _b;
691
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
692
- const reactions = (msg.pollUpdates || [])
693
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
694
- if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
1094
+ export const updateMessageWithPollUpdate = (msg, update) => {
1095
+ const authorID = getKeyAuthor(update.pollUpdateMessageKey);
1096
+ const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
1097
+ if (update.vote?.selectedOptions?.length) {
695
1098
  reactions.push(update);
696
1099
  }
697
1100
  msg.pollUpdates = reactions;
698
1101
  };
699
- exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
1102
+ /** Update the message with a new event response */
1103
+ export const updateMessageWithEventResponse = (msg, update) => {
1104
+ const authorID = getKeyAuthor(update.eventResponseMessageKey);
1105
+ const responses = (msg.eventResponses || []).filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID);
1106
+ responses.push(update);
1107
+ msg.eventResponses = responses;
1108
+ };
700
1109
  /**
701
1110
  * Aggregates all poll updates in a poll.
702
1111
  * @param msg the poll creation message
703
1112
  * @param meId your jid
704
1113
  * @returns A list of options & their voters
705
1114
  */
706
- function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
707
- var _a, _b, _c;
708
- 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) || [];
1115
+ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1116
+ const opts = message?.pollCreationMessage?.options ||
1117
+ message?.pollCreationMessageV2?.options ||
1118
+ message?.pollCreationMessageV3?.options ||
1119
+ [];
709
1120
  const voteHashMap = opts.reduce((acc, opt) => {
710
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
1121
+ const hash = sha256(Buffer.from(opt.optionName || '')).toString();
711
1122
  acc[hash] = {
712
1123
  name: opt.optionName || '',
713
1124
  voters: []
@@ -729,14 +1140,36 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
729
1140
  };
730
1141
  data = voteHashMap[hash];
731
1142
  }
732
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1143
+ voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
733
1144
  }
734
1145
  }
735
1146
  return Object.values(voteHashMap);
736
1147
  }
737
- exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
1148
+ /**
1149
+ * Aggregates all event responses in an event message.
1150
+ * @param msg the event creation message
1151
+ * @param meId your jid
1152
+ * @returns A list of response types & their responders
1153
+ */
1154
+ export function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1155
+ const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
1156
+ const responseMap = {};
1157
+ for (const type of responseTypes) {
1158
+ responseMap[type] = {
1159
+ response: type,
1160
+ responders: []
1161
+ };
1162
+ }
1163
+ for (const update of eventResponses || []) {
1164
+ const responseType = update.eventResponse || 'UNKNOWN';
1165
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1166
+ responseMap[responseType].responders.push(getKeyAuthor(update.eventResponseMessageKey, meId));
1167
+ }
1168
+ }
1169
+ return Object.values(responseMap);
1170
+ }
738
1171
  /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
739
- const aggregateMessageKeysNotFromMe = (keys) => {
1172
+ export const aggregateMessageKeysNotFromMe = (keys) => {
740
1173
  const keyMap = {};
741
1174
  for (const { remoteJid, id, participant, fromMe } of keys) {
742
1175
  if (!fromMe) {
@@ -753,40 +1186,34 @@ const aggregateMessageKeysNotFromMe = (keys) => {
753
1186
  }
754
1187
  return Object.values(keyMap);
755
1188
  };
756
- exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
757
1189
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
758
1190
  /**
759
1191
  * Downloads the given message. Throws an error if it's not a media message
760
1192
  */
761
- const downloadMediaMessage = async (message, type, options, ctx) => {
762
- const result = await downloadMsg()
763
- .catch(async (error) => {
764
- var _a;
765
- if (ctx) {
766
- if (axios_1.default.isAxiosError(error)) {
767
- // check if the message requires a reupload
768
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
769
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
770
- // request reupload
771
- message = await ctx.reuploadRequest(message);
772
- const result = await downloadMsg();
773
- return result;
774
- }
775
- }
1193
+ export const downloadMediaMessage = async (message, type, options, ctx) => {
1194
+ const result = await downloadMsg().catch(async (error) => {
1195
+ if (ctx &&
1196
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1197
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1198
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1199
+ // request reupload
1200
+ message = await ctx.reuploadRequest(message);
1201
+ const result = await downloadMsg();
1202
+ return result;
776
1203
  }
777
1204
  throw error;
778
1205
  });
779
1206
  return result;
780
1207
  async function downloadMsg() {
781
- const mContent = (0, exports.extractMessageContent)(message.message);
1208
+ const mContent = extractMessageContent(message.message);
782
1209
  if (!mContent) {
783
- throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
1210
+ throw new Boom('No message present', { statusCode: 400, data: message });
784
1211
  }
785
- const contentType = (0, exports.getContentType)(mContent);
786
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
1212
+ const contentType = getContentType(mContent);
1213
+ let mediaType = contentType?.replace('Message', '');
787
1214
  const media = mContent[contentType];
788
1215
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
789
- throw new boom_1.Boom(`"${contentType}" message is not a media message`);
1216
+ throw new Boom(`"${contentType}" message is not a media message`);
790
1217
  }
791
1218
  let download;
792
1219
  if ('thumbnailDirectPath' in media && !('url' in media)) {
@@ -799,7 +1226,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
799
1226
  else {
800
1227
  download = media;
801
1228
  }
802
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
1229
+ const stream = await downloadContentFromMessage(download, mediaType, options);
803
1230
  if (type === 'buffer') {
804
1231
  const bufferArray = [];
805
1232
  for await (const chunk of stream) {
@@ -810,18 +1237,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
810
1237
  return stream;
811
1238
  }
812
1239
  };
813
- exports.downloadMediaMessage = downloadMediaMessage;
814
1240
  /** Checks whether the given message is a media message; if it is returns the inner content */
815
- const assertMediaContent = (content) => {
816
- content = (0, exports.extractMessageContent)(content);
817
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
818
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
819
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
820
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
821
- || (content === null || content === void 0 ? void 0 : content.stickerMessage);
1241
+ export const assertMediaContent = (content) => {
1242
+ content = extractMessageContent(content);
1243
+ const mediaContent = content?.documentMessage ||
1244
+ content?.imageMessage ||
1245
+ content?.videoMessage ||
1246
+ content?.audioMessage ||
1247
+ content?.stickerMessage;
822
1248
  if (!mediaContent) {
823
- throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
1249
+ throw new Boom('given message is not a media message', { statusCode: 400, data: content });
824
1250
  }
825
1251
  return mediaContent;
826
1252
  };
827
- exports.assertMediaContent = assertMediaContent;
1253
+ //# sourceMappingURL=messages.js.map