@badzz88/baileys 8.3.0 → 8.4.1

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 (213) hide show
  1. package/README.md +27 -27
  2. package/WAProto/GenerateStatics.sh +3 -0
  3. package/WAProto/WAProto.proto +6902 -0
  4. package/WAProto/fix-import.js +29 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.d.ts +79257 -0
  7. package/WAProto/index.js +204305 -131020
  8. package/engine-requirements.js +3 -4
  9. package/lib/Defaults/baileys-version.json +1 -1
  10. package/lib/Defaults/index.js +119 -136
  11. package/lib/Signal/Group/ciphertext-message.js +2 -5
  12. package/lib/Signal/Group/group-session-builder.js +7 -41
  13. package/lib/Signal/Group/group_cipher.js +37 -51
  14. package/lib/Signal/Group/index.js +12 -57
  15. package/lib/Signal/Group/keyhelper.js +7 -44
  16. package/lib/Signal/Group/sender-chain-key.js +7 -15
  17. package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
  18. package/lib/Signal/Group/sender-key-message.js +9 -12
  19. package/lib/Signal/Group/sender-key-name.js +2 -5
  20. package/lib/Signal/Group/sender-key-record.js +9 -21
  21. package/lib/Signal/Group/sender-key-state.js +27 -42
  22. package/lib/Signal/Group/sender-message-key.js +4 -7
  23. package/lib/Signal/libsignal.js +347 -90
  24. package/lib/Signal/lid-mapping.js +277 -0
  25. package/lib/Socket/Client/index.js +3 -19
  26. package/lib/Socket/Client/types.js +11 -0
  27. package/lib/Socket/Client/websocket.js +54 -0
  28. package/lib/Socket/business.js +162 -43
  29. package/lib/Socket/chats.js +627 -404
  30. package/lib/Socket/communities.js +431 -0
  31. package/lib/Socket/community.js +392 -0
  32. package/lib/Socket/dugong.js +161 -8
  33. package/lib/Socket/groups.js +154 -160
  34. package/lib/Socket/index.js +11 -10
  35. package/lib/Socket/luxu.js +387 -0
  36. package/lib/Socket/messages-recv.js +1421 -615
  37. package/lib/Socket/messages-send.js +1150 -624
  38. package/lib/Socket/mex.js +42 -0
  39. package/lib/Socket/newsletter.js +139 -314
  40. package/lib/Socket/registration.js +2 -1
  41. package/lib/Socket/socket.js +544 -242
  42. package/lib/Store/index.js +10 -10
  43. package/lib/Store/keyed-db.js +108 -0
  44. package/lib/Store/make-cache-manager-store.js +43 -41
  45. package/lib/Store/make-in-memory-store.js +112 -341
  46. package/lib/Store/make-ordered-dictionary.js +14 -20
  47. package/lib/Store/object-repository.js +11 -6
  48. package/lib/Types/Auth.js +2 -2
  49. package/lib/Types/Bussines.js +2 -0
  50. package/lib/Types/Call.js +2 -2
  51. package/lib/Types/Chat.js +8 -4
  52. package/lib/Types/Contact.js +2 -2
  53. package/lib/Types/Events.js +2 -2
  54. package/lib/Types/GroupMetadata.js +2 -2
  55. package/lib/Types/Label.js +3 -5
  56. package/lib/Types/LabelAssociation.js +3 -5
  57. package/lib/Types/Message.js +11 -9
  58. package/lib/Types/Mex.js +37 -0
  59. package/lib/Types/Product.js +2 -2
  60. package/lib/Types/Signal.js +2 -2
  61. package/lib/Types/Socket.js +3 -2
  62. package/lib/Types/State.js +56 -2
  63. package/lib/Types/USync.js +2 -2
  64. package/lib/Types/index.js +15 -31
  65. package/lib/Utils/auth-utils.js +239 -143
  66. package/lib/Utils/browser-utils.js +48 -0
  67. package/lib/Utils/business.js +66 -69
  68. package/lib/Utils/chat-utils.js +396 -253
  69. package/lib/Utils/companion-reg-client-utils.js +35 -0
  70. package/lib/Utils/crypto.js +57 -90
  71. package/lib/Utils/decode-wa-message.js +236 -84
  72. package/lib/Utils/event-buffer.js +185 -77
  73. package/lib/Utils/generics.js +188 -283
  74. package/lib/Utils/history.js +93 -55
  75. package/lib/Utils/identity-change-handler.js +50 -0
  76. package/lib/Utils/index.js +23 -33
  77. package/lib/Utils/link-preview.js +16 -24
  78. package/lib/Utils/logger.js +3 -7
  79. package/lib/Utils/lt-hash.js +3 -46
  80. package/lib/Utils/make-mutex.js +24 -34
  81. package/lib/Utils/message-composer.js +273 -0
  82. package/lib/Utils/message-retry-manager.js +265 -0
  83. package/lib/Utils/messages-media.js +451 -482
  84. package/lib/Utils/messages.js +796 -359
  85. package/lib/Utils/noise-handler.js +145 -99
  86. package/lib/Utils/offline-node-processor.js +40 -0
  87. package/lib/Utils/pre-key-manager.js +106 -0
  88. package/lib/Utils/process-message.js +459 -150
  89. package/lib/Utils/reporting-utils.js +258 -0
  90. package/lib/Utils/signal.js +120 -72
  91. package/lib/Utils/stanza-ack.js +38 -0
  92. package/lib/Utils/sync-action-utils.js +49 -0
  93. package/lib/Utils/tc-token-utils.js +163 -0
  94. package/lib/Utils/use-multi-file-auth-state.js +29 -27
  95. package/lib/Utils/validate-connection.js +73 -99
  96. package/lib/WABinary/constants.js +1281 -20
  97. package/lib/WABinary/decode.js +52 -42
  98. package/lib/WABinary/encode.js +110 -155
  99. package/lib/WABinary/generic-utils.js +55 -49
  100. package/lib/WABinary/index.js +6 -21
  101. package/lib/WABinary/jid-utils.js +76 -40
  102. package/lib/WABinary/types.js +2 -2
  103. package/lib/WAM/BinaryInfo.js +2 -5
  104. package/lib/WAM/constants.js +19071 -11568
  105. package/lib/WAM/encode.js +17 -22
  106. package/lib/WAM/index.js +4 -19
  107. package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
  108. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
  109. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
  110. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
  111. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  112. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
  113. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
  114. package/lib/WAUSync/Protocols/index.js +6 -20
  115. package/lib/WAUSync/USyncQuery.js +44 -35
  116. package/lib/WAUSync/USyncUser.js +10 -5
  117. package/lib/WAUSync/index.js +4 -19
  118. package/lib/index.js +39 -53
  119. package/package.json +134 -101
  120. package/lib/Defaults/index.d.ts +0 -53
  121. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  122. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  123. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  124. package/lib/Signal/Group/index.d.ts +0 -11
  125. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  126. package/lib/Signal/Group/queue-job.d.ts +0 -1
  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/index.d.ts +0 -3
  137. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  138. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  139. package/lib/Socket/business.d.ts +0 -171
  140. package/lib/Socket/chats.d.ts +0 -267
  141. package/lib/Socket/dugong.d.ts +0 -254
  142. package/lib/Socket/groups.d.ts +0 -115
  143. package/lib/Socket/index.d.ts +0 -173
  144. package/lib/Socket/messages-recv.d.ts +0 -161
  145. package/lib/Socket/messages-send.d.ts +0 -149
  146. package/lib/Socket/newsletter.d.ts +0 -134
  147. package/lib/Socket/registration.d.ts +0 -267
  148. package/lib/Socket/socket.d.ts +0 -43
  149. package/lib/Socket/usync.d.ts +0 -36
  150. package/lib/Store/index.d.ts +0 -3
  151. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  152. package/lib/Store/make-in-memory-store.d.ts +0 -118
  153. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  154. package/lib/Store/object-repository.d.ts +0 -10
  155. package/lib/Types/Auth.d.ts +0 -110
  156. package/lib/Types/Call.d.ts +0 -13
  157. package/lib/Types/Chat.d.ts +0 -102
  158. package/lib/Types/Contact.d.ts +0 -19
  159. package/lib/Types/Events.d.ts +0 -157
  160. package/lib/Types/GroupMetadata.d.ts +0 -55
  161. package/lib/Types/Label.d.ts +0 -35
  162. package/lib/Types/LabelAssociation.d.ts +0 -29
  163. package/lib/Types/Message.d.ts +0 -273
  164. package/lib/Types/Newsletter.d.ts +0 -103
  165. package/lib/Types/Product.d.ts +0 -78
  166. package/lib/Types/Signal.d.ts +0 -57
  167. package/lib/Types/Socket.d.ts +0 -111
  168. package/lib/Types/State.d.ts +0 -27
  169. package/lib/Types/USync.d.ts +0 -25
  170. package/lib/Types/index.d.ts +0 -57
  171. package/lib/Utils/auth-utils.d.ts +0 -18
  172. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  173. package/lib/Utils/business.d.ts +0 -22
  174. package/lib/Utils/chat-utils.d.ts +0 -71
  175. package/lib/Utils/crypto.d.ts +0 -41
  176. package/lib/Utils/decode-wa-message.d.ts +0 -19
  177. package/lib/Utils/event-buffer.d.ts +0 -35
  178. package/lib/Utils/generics.d.ts +0 -92
  179. package/lib/Utils/history.d.ts +0 -15
  180. package/lib/Utils/index.d.ts +0 -17
  181. package/lib/Utils/link-preview.d.ts +0 -21
  182. package/lib/Utils/logger.d.ts +0 -4
  183. package/lib/Utils/lt-hash.d.ts +0 -12
  184. package/lib/Utils/make-mutex.d.ts +0 -7
  185. package/lib/Utils/messages-media.d.ts +0 -116
  186. package/lib/Utils/messages.d.ts +0 -77
  187. package/lib/Utils/noise-handler.d.ts +0 -21
  188. package/lib/Utils/process-message.d.ts +0 -41
  189. package/lib/Utils/signal.d.ts +0 -32
  190. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  191. package/lib/Utils/validate-connection.d.ts +0 -11
  192. package/lib/WABinary/constants.d.ts +0 -30
  193. package/lib/WABinary/decode.d.ts +0 -7
  194. package/lib/WABinary/encode.d.ts +0 -3
  195. package/lib/WABinary/generic-utils.d.ts +0 -17
  196. package/lib/WABinary/index.d.ts +0 -5
  197. package/lib/WABinary/jid-utils.d.ts +0 -31
  198. package/lib/WABinary/types.d.ts +0 -18
  199. package/lib/WAM/BinaryInfo.d.ts +0 -17
  200. package/lib/WAM/constants.d.ts +0 -38
  201. package/lib/WAM/encode.d.ts +0 -3
  202. package/lib/WAM/index.d.ts +0 -3
  203. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  204. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  205. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  206. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  207. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  208. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  209. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  210. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  211. package/lib/WAUSync/USyncUser.d.ts +0 -12
  212. package/lib/WAUSync/index.d.ts +0 -3
  213. 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,235 +186,460 @@ 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: "120363420249672073@newsletter",
109
- serverMessageId: 0,
110
- newsletterName: "kyuu ilysm",
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
  })
224
336
  });
225
-
226
337
  if (uploadData.ptv) {
227
338
  obj.ptvMessage = obj.videoMessage;
228
339
  delete obj.videoMessage;
229
340
  }
230
-
231
341
  if (cacheableKey) {
232
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
233
- 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());
234
344
  }
235
-
236
345
  return obj;
237
346
  };
238
- exports.prepareWAMessageMedia = prepareWAMessageMedia;
239
- const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
347
+ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
240
348
  ephemeralExpiration = ephemeralExpiration || 0;
241
349
  const content = {
242
350
  ephemeralMessage: {
243
351
  message: {
244
352
  protocolMessage: {
245
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
353
+ type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
246
354
  ephemeralExpiration
247
355
  }
248
356
  }
249
357
  }
250
358
  };
251
- return Types_1.WAProto.Message.fromObject(content);
359
+ return WAProto.Message.fromObject(content);
252
360
  };
253
- exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
254
361
  /**
255
362
  * Generate forwarded message content like WA does
256
363
  * @param message the message to forward
257
364
  * @param options.forceForward will show the message as forwarded even if it is from you
258
365
  */
259
- const generateForwardMessageContent = (message, forceForward) => {
260
- var _a;
366
+ export const generateForwardMessageContent = (message, forceForward) => {
261
367
  let content = message.message;
262
368
  if (!content) {
263
- throw new boom_1.Boom('no content in message', { statusCode: 400 });
369
+ throw new Boom('no content in message', { statusCode: 400 });
264
370
  }
265
371
  // hacky copy
266
- content = (0, exports.normalizeMessageContent)(content);
267
- 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());
268
374
  let key = Object.keys(content)[0];
269
- let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
375
+ let score = content?.[key]?.contextInfo?.forwardingScore || 0;
270
376
  score += message.key.fromMe && !forceForward ? 0 : 1;
271
377
  if (key === 'conversation') {
272
378
  content.extendedTextMessage = { text: content[key] };
273
379
  delete content.conversation;
274
380
  key = 'extendedTextMessage';
275
381
  }
382
+ const key_ = content?.[key];
276
383
  if (score > 0) {
277
- content[key].contextInfo = { forwardingScore: score, isForwarded: true };
384
+ key_.contextInfo = { forwardingScore: score, isForwarded: true };
278
385
  }
279
386
  else {
280
- content[key].contextInfo = {};
387
+ key_.contextInfo = {};
281
388
  }
282
389
  return content;
283
390
  };
284
- exports.generateForwardMessageContent = generateForwardMessageContent;
285
- const generateWAMessageContent = async (message, options) => {
286
- var _a;
287
- 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;
288
414
  let m = {};
289
- 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')) {
290
637
  const extContent = { text: message.text };
291
638
  let urlInfo = message.linkPreview;
292
639
  if (typeof urlInfo === 'undefined') {
293
- urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
640
+ urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
294
641
  }
295
642
  if (urlInfo) {
296
- extContent.canonicalUrl = urlInfo['canonical-url'];
297
643
  extContent.matchedText = urlInfo['matched-text'];
298
644
  extContent.jpegThumbnail = urlInfo.jpegThumbnail;
299
645
  extContent.description = urlInfo.description;
@@ -318,206 +664,274 @@ const generateWAMessageContent = async (message, options) => {
318
664
  }
319
665
  m.extendedTextMessage = extContent;
320
666
  }
321
- else if ('contacts' in message) {
667
+ else if (hasNonNullishProperty(message, 'contacts')) {
322
668
  const contactLen = message.contacts.contacts.length;
323
669
  if (!contactLen) {
324
- throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
670
+ throw new Boom('require atleast 1 contact', { statusCode: 400 });
325
671
  }
326
672
  if (contactLen === 1) {
327
- m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0]);
673
+ m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
328
674
  }
329
675
  else {
330
- m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts);
676
+ m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
331
677
  }
332
678
  }
333
- else if ('location' in message) {
334
- m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
679
+ else if (hasNonNullishProperty(message, 'location')) {
680
+ m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
335
681
  }
336
- else if ('react' in message) {
682
+ else if (hasNonNullishProperty(message, 'react')) {
337
683
  if (!message.react.senderTimestampMs) {
338
684
  message.react.senderTimestampMs = Date.now();
339
685
  }
340
- m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
686
+ m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
341
687
  }
342
- else if ('delete' in message) {
688
+ else if (hasNonNullishProperty(message, 'delete')) {
343
689
  m.protocolMessage = {
344
690
  key: message.delete,
345
- type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
691
+ type: WAProto.Message.ProtocolMessage.Type.REVOKE
346
692
  };
347
693
  }
348
- else if ('forward' in message) {
349
- 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
+ }
350
724
  }
351
- else if ('disappearingMessagesInChat' in message) {
352
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
353
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
354
- message.disappearingMessagesInChat;
355
- 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;
356
732
  }
357
- else if ('buttonReply' in message) {
733
+ else if (hasNonNullishProperty(message, 'buttonReply')) {
358
734
  switch (message.type) {
359
735
  case 'template':
360
736
  m.templateButtonReplyMessage = {
361
737
  selectedDisplayText: message.buttonReply.displayText,
362
738
  selectedId: message.buttonReply.id,
363
- selectedIndex: message.buttonReply.index,
739
+ selectedIndex: message.buttonReply.index
364
740
  };
365
741
  break;
366
742
  case 'plain':
367
743
  m.buttonsResponseMessage = {
368
744
  selectedButtonId: message.buttonReply.id,
369
745
  selectedDisplayText: message.buttonReply.displayText,
370
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
746
+ type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
371
747
  };
372
748
  break;
373
749
  }
374
750
  }
375
- else if ('product' in message) {
376
- const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
377
- 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({
378
758
  ...message,
379
759
  product: {
380
760
  ...message.product,
381
- productImage: imageMessage,
761
+ productImage: imageMessage
382
762
  }
383
763
  });
384
764
  }
385
- else if ('listReply' in message) {
765
+ else if (hasNonNullishProperty(message, 'listReply')) {
386
766
  m.listResponseMessage = { ...message.listReply };
387
767
  }
388
- else if ('poll' in message) {
389
- (_b = message.poll).selectableCount || (_b.selectableCount = 0);
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;
787
+ }
788
+ else if (hasNonNullishProperty(message, 'poll')) {
789
+ (_a = message.poll).selectableCount || (_a.selectableCount = 0);
790
+ (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
390
791
  if (!Array.isArray(message.poll.values)) {
391
- throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
792
+ throw new Boom('Invalid poll values', { statusCode: 400 });
392
793
  }
393
- if (message.poll.selectableCount < 0
394
- || message.poll.selectableCount > message.poll.values.length) {
395
- 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
+ });
396
798
  }
397
799
  m.messageContextInfo = {
398
800
  // encKey
399
- messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
801
+ messageSecret: message.poll.messageSecret || randomBytes(32)
400
802
  };
401
- m.pollCreationMessage = {
803
+ const pollCreationMessage = {
402
804
  name: message.poll.name,
403
805
  selectableOptionsCount: message.poll.selectableCount,
404
- options: message.poll.values.map(optionName => ({ optionName })),
806
+ options: message.poll.values.map(optionName => ({ optionName }))
405
807
  };
406
- }
407
- else if ('sharePhoneNumber' in message) {
408
- m.protocolMessage = {
409
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
410
- };
411
- }
412
- else if ('requestPhoneNumber' in message) {
413
- m.requestPhoneNumberMessage = {};
414
- }
415
- else {
416
- m = await (0, exports.prepareWAMessageMedia)(message, options);
417
- }
418
- if ('buttons' in message && !!message.buttons) {
419
- const buttonsMessage = {
420
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
421
- };
422
- if ('text' in message) {
423
- buttonsMessage.contentText = message.text;
424
- 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;
425
811
  }
426
812
  else {
427
- if ('caption' in message) {
428
- 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;
429
820
  }
430
- const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
431
- buttonsMessage.headerType = ButtonType[type];
432
- Object.assign(buttonsMessage, m);
433
- }
434
- if ('footer' in message && !!message.footer) {
435
- buttonsMessage.footerText = message.footer;
436
821
  }
437
- m = { buttonsMessage };
438
822
  }
439
- else if ('templateButtons' in message && !!message.templateButtons) {
440
- const msg = {
441
- hydratedButtons: message.templateButtons
823
+ else if (hasNonNullishProperty(message, 'album')) {
824
+ m.albumMessage = {
825
+ expectedImageCount: message.album.expectedImageCount,
826
+ expectedVideoCount: message.album.expectedVideoCount
442
827
  };
443
- if ('text' in message) {
444
- msg.hydratedContentText = message.text;
445
- }
446
- else {
447
- if ('caption' in message) {
448
- msg.hydratedContentText = message.caption;
449
- }
450
- Object.assign(msg, m);
451
- }
452
- if ('footer' in message && !!message.footer) {
453
- msg.hydratedFooterText = message.footer;
454
- }
455
- m = {
456
- templateMessage: {
457
- fourRowTemplate: msg,
458
- hydratedTemplate: msg
459
- }
828
+ }
829
+ else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
830
+ m.protocolMessage = {
831
+ type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
460
832
  };
461
833
  }
462
- if ('sections' in message && !!message.sections) {
463
- const listMessage = {
464
- sections: message.sections,
465
- buttonText: message.buttonText,
466
- title: message.title,
467
- footerText: message.footer,
468
- description: message.text,
469
- 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
+ }
470
846
  };
471
- m = { listMessage };
472
847
  }
473
- if ('viewOnce' in message && !!message.viewOnce) {
848
+ else {
849
+ m = await prepareWAMessageMedia(message, options);
850
+ }
851
+ if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
474
852
  m = { viewOnceMessage: { message: m } };
475
853
  }
476
- if ('mentions' in message && ((_a = message.mentions) === null || _a === void 0 ? void 0 : _a.length)) {
477
- const [messageType] = Object.keys(m);
478
- m[messageType].contextInfo = m[messageType] || {};
479
- 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
+ }
480
873
  }
481
- if ('edit' in message) {
874
+ if (hasOptionalProperty(message, 'edit')) {
482
875
  m = {
483
876
  protocolMessage: {
484
877
  key: message.edit,
485
878
  editedMessage: m,
486
879
  timestampMs: Date.now(),
487
- 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
488
900
  }
489
901
  };
490
902
  }
491
- if ('contextInfo' in message && !!message.contextInfo) {
492
- const [messageType] = Object.keys(m);
493
- m[messageType] = m[messageType] || {};
494
- 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
+ }
495
908
  }
496
- return Types_1.WAProto.Message.fromObject(m);
909
+ return WAProto.Message.create(m);
497
910
  };
498
- exports.generateWAMessageContent = generateWAMessageContent;
499
- const generateWAMessageFromContent = (jid, message, options) => {
911
+ export const generateWAMessageFromContent = (jid, message, options) => {
500
912
  // set timestamp to now
501
913
  // if not specified
502
914
  if (!options.timestamp) {
503
915
  options.timestamp = new Date();
504
916
  }
505
- const innerMessage = (0, exports.normalizeMessageContent)(message);
506
- const key = (0, exports.getContentType)(innerMessage);
507
- const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
917
+ const innerMessage = normalizeMessageContent(message);
918
+ const key = getContentType(innerMessage);
919
+ const timestamp = unixTimestampSeconds(options.timestamp);
508
920
  const { quoted, userJid } = options;
509
- if (quoted && !(0, WABinary_1.isJidNewsLetter)(jid)) {
510
- const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
511
- let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
512
- 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);
513
927
  // strip any redundant properties
514
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
928
+ quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
515
929
  const quotedContent = quotedMsg[msgType];
516
930
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
517
931
  delete quotedContent.contextInfo;
518
932
  }
519
- const contextInfo = innerMessage[key].contextInfo || {};
520
- contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
933
+ const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
934
+ contextInfo.participant = jidNormalizedUser(participant);
521
935
  contextInfo.stanzaId = quoted.key.id;
522
936
  contextInfo.quotedMessage = quotedMsg;
523
937
  // if a participant is quoted, then it must be a group
@@ -525,62 +939,63 @@ const generateWAMessageFromContent = (jid, message, options) => {
525
939
  if (jid !== quoted.key.remoteJid) {
526
940
  contextInfo.remoteJid = quoted.key.remoteJid;
527
941
  }
528
- innerMessage[key].contextInfo = contextInfo;
942
+ if (contextInfo && innerMessage[key]) {
943
+ /* @ts-ignore */
944
+ innerMessage[key].contextInfo = contextInfo;
945
+ }
529
946
  }
530
947
  if (
531
948
  // if we want to send a disappearing message
532
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
949
+ !!options?.ephemeralExpiration &&
533
950
  // and it's not a protocol message -- delete, toggle disappear message
534
951
  key !== 'protocolMessage' &&
535
952
  // already not converted to disappearing message
536
953
  key !== 'ephemeralMessage' &&
537
- // newsletter not accept disappearing messages
538
- !(0, WABinary_1.isJidNewsLetter)(jid)) {
954
+ // newsletters don't support ephemeral messages
955
+ !isJidNewsletter(jid)) {
956
+ /* @ts-ignore */
539
957
  innerMessage[key].contextInfo = {
540
958
  ...(innerMessage[key].contextInfo || {}),
541
- expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
959
+ expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
542
960
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
543
961
  };
544
962
  }
545
- message = Types_1.WAProto.Message.fromObject(message);
963
+ message = WAProto.Message.create(message);
546
964
  const messageJSON = {
547
965
  key: {
548
966
  remoteJid: jid,
549
967
  fromMe: true,
550
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
968
+ id: options?.messageId || generateMessageIDV2()
551
969
  },
552
970
  message: message,
553
971
  messageTimestamp: timestamp,
554
972
  messageStubParameters: [],
555
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
556
- status: Types_1.WAMessageStatus.PENDING
973
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
974
+ status: WAMessageStatus.PENDING
557
975
  };
558
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
976
+ return WAProto.WebMessageInfo.fromObject(messageJSON);
559
977
  };
560
- exports.generateWAMessageFromContent = generateWAMessageFromContent;
561
- const generateWAMessage = async (jid, content, options) => {
562
- var _a;
978
+ export const generateWAMessage = async (jid, content, options) => {
563
979
  // ensure msg ID is with every log
564
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
565
- 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);
566
983
  };
567
- exports.generateWAMessage = generateWAMessage;
568
984
  /** Get the key to access the true type of content */
569
- const getContentType = (content) => {
985
+ export const getContentType = (content) => {
570
986
  if (content) {
571
987
  const keys = Object.keys(content);
572
988
  const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
573
989
  return key;
574
990
  }
575
991
  };
576
- exports.getContentType = getContentType;
577
992
  /**
578
993
  * Normalizes ephemeral, view once messages to regular message content
579
994
  * Eg. image messages in ephemeral messages, in view once messages etc.
580
995
  * @param content
581
996
  * @returns
582
997
  */
583
- const normalizeMessageContent = (content) => {
998
+ export const normalizeMessageContent = (content) => {
584
999
  if (!content) {
585
1000
  return undefined;
586
1001
  }
@@ -594,21 +1009,22 @@ const normalizeMessageContent = (content) => {
594
1009
  }
595
1010
  return content;
596
1011
  function getFutureProofMessage(message) {
597
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
598
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
599
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
600
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
601
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
602
- || (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);
603
1021
  }
604
1022
  };
605
- exports.normalizeMessageContent = normalizeMessageContent;
606
1023
  /**
607
1024
  * Extract the true message content from a message
608
1025
  * Eg. extracts the inner message from a disappearing message/view once message
609
1026
  */
610
- const extractMessageContent = (content) => {
611
- var _a, _b, _c, _d, _e, _f;
1027
+ export const extractMessageContent = (content) => {
612
1028
  const extractFromTemplateMessage = (msg) => {
613
1029
  if (msg.imageMessage) {
614
1030
  return { imageMessage: msg.imageMessage };
@@ -624,35 +1040,39 @@ const extractMessageContent = (content) => {
624
1040
  }
625
1041
  else {
626
1042
  return {
627
- conversation: 'contentText' in msg
628
- ? msg.contentText
629
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
1043
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
630
1044
  };
631
1045
  }
632
1046
  };
633
- content = (0, exports.normalizeMessageContent)(content);
634
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
1047
+ content = normalizeMessageContent(content);
1048
+ if (content?.buttonsMessage) {
635
1049
  return extractFromTemplateMessage(content.buttonsMessage);
636
1050
  }
637
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
638
- 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);
639
1053
  }
640
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
641
- 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);
642
1056
  }
643
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
644
- 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);
645
1059
  }
646
1060
  return content;
647
1061
  };
648
- exports.extractMessageContent = extractMessageContent;
649
1062
  /**
650
1063
  * Returns the device predicted by message ID
651
1064
  */
652
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' : /^3E.{20}$/.test(id) ? 'web' : /^(.{21}|.{32})$/.test(id) ? 'android' : /^.{18}$/.test(id) ? 'desktop' : 'unknown';
653
- 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';
654
1074
  /** Upserts a receipt in the message */
655
- const updateMessageWithReceipt = (msg, receipt) => {
1075
+ export const updateMessageWithReceipt = (msg, receipt) => {
656
1076
  msg.userReceipt = msg.userReceipt || [];
657
1077
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
658
1078
  if (recp) {
@@ -662,41 +1082,43 @@ const updateMessageWithReceipt = (msg, receipt) => {
662
1082
  msg.userReceipt.push(receipt);
663
1083
  }
664
1084
  };
665
- exports.updateMessageWithReceipt = updateMessageWithReceipt;
666
1085
  /** Update the message with a new reaction */
667
- const updateMessageWithReaction = (msg, reaction) => {
668
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
669
- const reactions = (msg.reactions || [])
670
- .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
671
- if (reaction.text) {
672
- reactions.push(reaction);
673
- }
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);
674
1091
  msg.reactions = reactions;
675
1092
  };
676
- exports.updateMessageWithReaction = updateMessageWithReaction;
677
1093
  /** Update the message with a new poll update */
678
- const updateMessageWithPollUpdate = (msg, update) => {
679
- var _a, _b;
680
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
681
- const reactions = (msg.pollUpdates || [])
682
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
683
- 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) {
684
1098
  reactions.push(update);
685
1099
  }
686
1100
  msg.pollUpdates = reactions;
687
1101
  };
688
- 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
+ };
689
1109
  /**
690
1110
  * Aggregates all poll updates in a poll.
691
1111
  * @param msg the poll creation message
692
1112
  * @param meId your jid
693
1113
  * @returns A list of options & their voters
694
1114
  */
695
- function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
696
- var _a, _b, _c;
697
- 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
+ [];
698
1120
  const voteHashMap = opts.reduce((acc, opt) => {
699
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
1121
+ const hash = sha256(Buffer.from(opt.optionName || '')).toString();
700
1122
  acc[hash] = {
701
1123
  name: opt.optionName || '',
702
1124
  voters: []
@@ -718,14 +1140,36 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
718
1140
  };
719
1141
  data = voteHashMap[hash];
720
1142
  }
721
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1143
+ voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
722
1144
  }
723
1145
  }
724
1146
  return Object.values(voteHashMap);
725
1147
  }
726
- 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
+ }
727
1171
  /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
728
- const aggregateMessageKeysNotFromMe = (keys) => {
1172
+ export const aggregateMessageKeysNotFromMe = (keys) => {
729
1173
  const keyMap = {};
730
1174
  for (const { remoteJid, id, participant, fromMe } of keys) {
731
1175
  if (!fromMe) {
@@ -742,40 +1186,34 @@ const aggregateMessageKeysNotFromMe = (keys) => {
742
1186
  }
743
1187
  return Object.values(keyMap);
744
1188
  };
745
- exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
746
1189
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
747
1190
  /**
748
1191
  * Downloads the given message. Throws an error if it's not a media message
749
1192
  */
750
- const downloadMediaMessage = async (message, type, options, ctx) => {
751
- const result = await downloadMsg()
752
- .catch(async (error) => {
753
- var _a;
754
- if (ctx) {
755
- if (axios_1.default.isAxiosError(error)) {
756
- // check if the message requires a reupload
757
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
758
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
759
- // request reupload
760
- message = await ctx.reuploadRequest(message);
761
- const result = await downloadMsg();
762
- return result;
763
- }
764
- }
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;
765
1203
  }
766
1204
  throw error;
767
1205
  });
768
1206
  return result;
769
1207
  async function downloadMsg() {
770
- const mContent = (0, exports.extractMessageContent)(message.message);
1208
+ const mContent = extractMessageContent(message.message);
771
1209
  if (!mContent) {
772
- throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
1210
+ throw new Boom('No message present', { statusCode: 400, data: message });
773
1211
  }
774
- const contentType = (0, exports.getContentType)(mContent);
775
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
1212
+ const contentType = getContentType(mContent);
1213
+ let mediaType = contentType?.replace('Message', '');
776
1214
  const media = mContent[contentType];
777
1215
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
778
- throw new boom_1.Boom(`"${contentType}" message is not a media message`);
1216
+ throw new Boom(`"${contentType}" message is not a media message`);
779
1217
  }
780
1218
  let download;
781
1219
  if ('thumbnailDirectPath' in media && !('url' in media)) {
@@ -788,7 +1226,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
788
1226
  else {
789
1227
  download = media;
790
1228
  }
791
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
1229
+ const stream = await downloadContentFromMessage(download, mediaType, options);
792
1230
  if (type === 'buffer') {
793
1231
  const bufferArray = [];
794
1232
  for await (const chunk of stream) {
@@ -799,18 +1237,17 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
799
1237
  return stream;
800
1238
  }
801
1239
  };
802
- exports.downloadMediaMessage = downloadMediaMessage;
803
1240
  /** Checks whether the given message is a media message; if it is returns the inner content */
804
- const assertMediaContent = (content) => {
805
- content = (0, exports.extractMessageContent)(content);
806
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
807
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
808
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
809
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
810
- || (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;
811
1248
  if (!mediaContent) {
812
- 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 });
813
1250
  }
814
1251
  return mediaContent;
815
1252
  };
816
- exports.assertMediaContent = assertMediaContent;
1253
+ //# sourceMappingURL=messages.js.map