@fazzcode/baileys 0.1.7 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/LICENSE +21 -0
  2. package/WAProto/WAProto.proto +5311 -0
  3. package/WAProto/index.js +83385 -119575
  4. package/lib/Defaults/index.js +117 -124
  5. package/lib/KeyDB/BinarySearch.js +20 -0
  6. package/lib/KeyDB/KeyedDB.js +167 -0
  7. package/lib/KeyDB/index.js +4 -0
  8. package/lib/Signal/Group/ciphertext-message.js +12 -14
  9. package/lib/Signal/Group/group-session-builder.js +10 -42
  10. package/lib/Signal/Group/group_cipher.js +75 -87
  11. package/lib/Signal/Group/index.js +13 -57
  12. package/lib/Signal/Group/keyhelper.js +17 -52
  13. package/lib/Signal/Group/sender-chain-key.js +27 -33
  14. package/lib/Signal/Group/sender-key-distribution-message.js +62 -63
  15. package/lib/Signal/Group/sender-key-message.js +65 -66
  16. package/lib/Signal/Group/sender-key-name.js +45 -44
  17. package/lib/Signal/Group/sender-key-record.js +39 -49
  18. package/lib/Signal/Group/sender-key-state.js +80 -93
  19. package/lib/Signal/Group/sender-message-key.js +27 -28
  20. package/lib/Signal/libsignal.js +313 -163
  21. package/lib/Signal/lid-mapping.js +155 -0
  22. package/lib/Socket/Client/index.js +4 -19
  23. package/lib/Socket/Client/types.js +13 -0
  24. package/lib/Socket/Client/websocket.js +52 -0
  25. package/lib/Socket/business.js +359 -242
  26. package/lib/Socket/chats.js +851 -830
  27. package/lib/Socket/communities.js +413 -0
  28. package/lib/Socket/groups.js +304 -309
  29. package/lib/Socket/index.js +15 -9
  30. package/lib/Socket/messages-recv.js +1107 -1054
  31. package/lib/Socket/messages-send.js +709 -414
  32. package/lib/Socket/mex.js +45 -0
  33. package/lib/Socket/newsletter.js +232 -318
  34. package/lib/Socket/socket.js +789 -599
  35. package/lib/Store/index.js +6 -10
  36. package/lib/Store/make-cache-manager-store.js +73 -81
  37. package/lib/Store/make-in-memory-store.js +286 -423
  38. package/lib/Store/make-ordered-dictionary.js +77 -79
  39. package/lib/Store/object-repository.js +24 -26
  40. package/lib/Types/Auth.js +3 -2
  41. package/lib/Types/Bussines.js +3 -0
  42. package/lib/Types/Call.js +3 -2
  43. package/lib/Types/Chat.js +9 -4
  44. package/lib/Types/Contact.js +3 -2
  45. package/lib/Types/Events.js +3 -2
  46. package/lib/Types/GroupMetadata.js +3 -2
  47. package/lib/Types/Label.js +24 -26
  48. package/lib/Types/LabelAssociation.js +6 -8
  49. package/lib/Types/Message.js +12 -9
  50. package/lib/Types/Newsletter.js +31 -30
  51. package/lib/Types/Newsletter.js.bak +33 -0
  52. package/lib/Types/Product.js +3 -2
  53. package/lib/Types/Signal.js +3 -2
  54. package/lib/Types/Socket.js +4 -2
  55. package/lib/Types/State.js +11 -2
  56. package/lib/Types/USync.js +3 -2
  57. package/lib/Types/index.js +27 -41
  58. package/lib/Utils/auth-utils.js +211 -198
  59. package/lib/Utils/baileys-event-stream.js +42 -61
  60. package/lib/Utils/browser-utils.js +25 -0
  61. package/lib/Utils/business.js +213 -214
  62. package/lib/Utils/chat-utils.js +710 -687
  63. package/lib/Utils/crypto.js +112 -133
  64. package/lib/Utils/decode-wa-message.js +252 -183
  65. package/lib/Utils/event-buffer.js +510 -496
  66. package/lib/Utils/generics.js +328 -356
  67. package/lib/Utils/history.js +83 -92
  68. package/lib/Utils/index.js +21 -33
  69. package/lib/Utils/link-preview.js +71 -83
  70. package/lib/Utils/logger.js +5 -7
  71. package/lib/Utils/lt-hash.js +40 -46
  72. package/lib/Utils/make-mutex.js +34 -41
  73. package/lib/Utils/message-retry-manager.js +113 -0
  74. package/lib/Utils/messages-media.js +548 -678
  75. package/lib/Utils/messages.js +352 -249
  76. package/lib/Utils/noise-handler.js +138 -149
  77. package/lib/Utils/pre-key-manager.js +85 -0
  78. package/lib/Utils/process-message.js +323 -303
  79. package/lib/Utils/signal.js +148 -138
  80. package/lib/Utils/use-multi-file-auth-state.js +98 -67
  81. package/lib/Utils/validate-connection.js +183 -188
  82. package/lib/WABinary/constants.js +1298 -35
  83. package/lib/WABinary/decode.js +237 -249
  84. package/lib/WABinary/encode.js +208 -218
  85. package/lib/WABinary/generic-utils.js +53 -57
  86. package/lib/WABinary/index.js +7 -21
  87. package/lib/WABinary/jid-utils.js +89 -58
  88. package/lib/WABinary/types.js +3 -2
  89. package/lib/WAM/BinaryInfo.js +10 -12
  90. package/lib/WAM/constants.js +22851 -15348
  91. package/lib/WAM/encode.js +135 -136
  92. package/lib/WAM/index.js +5 -19
  93. package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -30
  94. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +49 -53
  95. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -28
  96. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -39
  97. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -50
  98. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +26 -20
  99. package/lib/WAUSync/Protocols/index.js +6 -20
  100. package/lib/WAUSync/USyncQuery.js +86 -85
  101. package/lib/WAUSync/USyncUser.js +23 -25
  102. package/lib/WAUSync/index.js +5 -19
  103. package/lib/index.js +32 -34
  104. package/package.json +99 -105
  105. package/README.MD +0 -121
  106. package/engine-requirements.js +0 -10
  107. package/lib/Defaults/baileys-version.json +0 -3
  108. package/lib/Defaults/index.d.ts +0 -53
  109. package/lib/Defaults/phonenumber-mcc.json +0 -223
  110. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  111. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  112. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  113. package/lib/Signal/Group/index.d.ts +0 -11
  114. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  115. package/lib/Signal/Group/queue-job.d.ts +0 -1
  116. package/lib/Signal/Group/queue-job.js +0 -57
  117. package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
  118. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
  119. package/lib/Signal/Group/sender-key-message.d.ts +0 -18
  120. package/lib/Signal/Group/sender-key-name.d.ts +0 -17
  121. package/lib/Signal/Group/sender-key-record.d.ts +0 -30
  122. package/lib/Signal/Group/sender-key-state.d.ts +0 -38
  123. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  124. package/lib/Signal/libsignal.d.ts +0 -3
  125. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  126. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  127. package/lib/Socket/Client/index.d.ts +0 -3
  128. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  129. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  130. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  131. package/lib/Socket/Client/web-socket-client.js +0 -62
  132. package/lib/Socket/business.d.ts +0 -171
  133. package/lib/Socket/chats.d.ts +0 -80
  134. package/lib/Socket/dugong.d.ts +0 -219
  135. package/lib/Socket/dugong.js +0 -441
  136. package/lib/Socket/groups.d.ts +0 -115
  137. package/lib/Socket/index.d.ts +0 -173
  138. package/lib/Socket/messages-recv.d.ts +0 -161
  139. package/lib/Socket/messages-send.d.ts +0 -149
  140. package/lib/Socket/newsletter.d.ts +0 -134
  141. package/lib/Socket/registration.d.ts +0 -267
  142. package/lib/Socket/registration.js +0 -166
  143. package/lib/Socket/socket.d.ts +0 -43
  144. package/lib/Socket/usync.d.ts +0 -36
  145. package/lib/Socket/usync.js +0 -70
  146. package/lib/Store/index.d.ts +0 -3
  147. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  148. package/lib/Store/make-in-memory-store.d.ts +0 -118
  149. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  150. package/lib/Store/object-repository.d.ts +0 -10
  151. package/lib/Types/Auth.d.ts +0 -110
  152. package/lib/Types/Call.d.ts +0 -13
  153. package/lib/Types/Chat.d.ts +0 -102
  154. package/lib/Types/Contact.d.ts +0 -19
  155. package/lib/Types/Events.d.ts +0 -157
  156. package/lib/Types/GroupMetadata.d.ts +0 -55
  157. package/lib/Types/Label.d.ts +0 -35
  158. package/lib/Types/LabelAssociation.d.ts +0 -29
  159. package/lib/Types/Message.d.ts +0 -273
  160. package/lib/Types/Newsletter.d.ts +0 -92
  161. package/lib/Types/Product.d.ts +0 -78
  162. package/lib/Types/Signal.d.ts +0 -57
  163. package/lib/Types/Socket.d.ts +0 -111
  164. package/lib/Types/State.d.ts +0 -27
  165. package/lib/Types/USync.d.ts +0 -25
  166. package/lib/Types/index.d.ts +0 -57
  167. package/lib/Utils/auth-utils.d.ts +0 -18
  168. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  169. package/lib/Utils/business.d.ts +0 -22
  170. package/lib/Utils/chat-utils.d.ts +0 -71
  171. package/lib/Utils/crypto.d.ts +0 -41
  172. package/lib/Utils/decode-wa-message.d.ts +0 -19
  173. package/lib/Utils/event-buffer.d.ts +0 -35
  174. package/lib/Utils/generics.d.ts +0 -92
  175. package/lib/Utils/history.d.ts +0 -15
  176. package/lib/Utils/index.d.ts +0 -17
  177. package/lib/Utils/link-preview.d.ts +0 -21
  178. package/lib/Utils/logger.d.ts +0 -4
  179. package/lib/Utils/lt-hash.d.ts +0 -12
  180. package/lib/Utils/make-mutex.d.ts +0 -7
  181. package/lib/Utils/messages-media.d.ts +0 -116
  182. package/lib/Utils/messages.d.ts +0 -77
  183. package/lib/Utils/noise-handler.d.ts +0 -21
  184. package/lib/Utils/process-message.d.ts +0 -41
  185. package/lib/Utils/signal.d.ts +0 -32
  186. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  187. package/lib/Utils/validate-connection.d.ts +0 -11
  188. package/lib/WABinary/constants.d.ts +0 -27
  189. package/lib/WABinary/decode.d.ts +0 -7
  190. package/lib/WABinary/encode.d.ts +0 -3
  191. package/lib/WABinary/generic-utils.d.ts +0 -16
  192. package/lib/WABinary/index.d.ts +0 -5
  193. package/lib/WABinary/jid-utils.d.ts +0 -31
  194. package/lib/WABinary/types.d.ts +0 -18
  195. package/lib/WAM/BinaryInfo.d.ts +0 -17
  196. package/lib/WAM/constants.d.ts +0 -38
  197. package/lib/WAM/encode.d.ts +0 -3
  198. package/lib/WAM/index.d.ts +0 -3
  199. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  200. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  201. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  202. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  203. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  204. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  205. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  206. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  207. package/lib/WAUSync/USyncUser.d.ts +0 -12
  208. package/lib/WAUSync/index.d.ts +0 -3
  209. package/lib/index.d.ts +0 -12
@@ -1,56 +1,49 @@
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 { 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';
18
12
  const MIMETYPE_MAP = {
19
13
  image: 'image/jpeg',
20
14
  video: 'video/mp4',
21
15
  document: 'application/pdf',
22
16
  audio: 'audio/ogg; codecs=opus',
23
17
  sticker: 'image/webp',
24
- 'product-catalog-image': 'image/jpeg',
18
+ 'product-catalog-image': 'image/jpeg'
25
19
  };
26
20
  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,
21
+ image: WAProto.Message.ImageMessage,
22
+ video: WAProto.Message.VideoMessage,
23
+ audio: WAProto.Message.AudioMessage,
24
+ sticker: WAProto.Message.StickerMessage,
25
+ document: WAProto.Message.DocumentMessage
32
26
  };
33
- const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
27
+ const ButtonType = proto.Message.ButtonsMessage.HeaderType;
34
28
  /**
35
29
  * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
36
30
  * @param text eg. hello https://google.com
37
31
  * @returns the URL, eg. https://google.com
38
32
  */
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);
33
+ export const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0];
34
+ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
35
+ const url = extractUrlFromText(text);
43
36
  if (!!getUrlInfo && url) {
44
37
  try {
45
38
  const urlInfo = await getUrlInfo(url);
46
39
  return urlInfo;
47
40
  }
48
- catch (error) { // ignore if fails
49
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
41
+ catch (error) {
42
+ // ignore if fails
43
+ logger?.warn({ trace: error.stack }, 'url generation failed');
50
44
  }
51
45
  }
52
46
  };
53
- exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
54
47
  const assertColor = async (color) => {
55
48
  let assertedColor;
56
49
  if (typeof color === 'number') {
@@ -65,16 +58,16 @@ const assertColor = async (color) => {
65
58
  return assertedColor;
66
59
  }
67
60
  };
68
- const prepareWAMessageMedia = async (message, options) => {
61
+ export const prepareWAMessageMedia = async (message, options) => {
69
62
  const logger = options.logger;
70
63
  let mediaType;
71
- for (const key of Defaults_1.MEDIA_KEYS) {
64
+ for (const key of MEDIA_KEYS) {
72
65
  if (key in message) {
73
66
  mediaType = key;
74
67
  }
75
68
  }
76
69
  if (!mediaType) {
77
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
70
+ throw new Boom('Invalid media type', { statusCode: 400 });
78
71
  }
79
72
  const uploadData = {
80
73
  ...message,
@@ -102,9 +95,9 @@ const prepareWAMessageMedia = async (message, options) => {
102
95
  }
103
96
  ],
104
97
  newsletter: {
105
- newsletterJid: "120363297591152843@newsletter",
98
+ newsletterJid: "120363422054951473@newsletter",
106
99
  serverMessageId: 0,
107
- newsletterName: "-",
100
+ newsletterName: "skyzopedia",
108
101
  contentType: "UPDATE",
109
102
  }
110
103
  }
@@ -115,100 +108,132 @@ const prepareWAMessageMedia = async (message, options) => {
115
108
  delete uploadData[mediaType];
116
109
  // check if cacheable + generate cache key
117
110
  const cacheableKey = typeof uploadData.media === 'object' &&
118
- ('url' in uploadData.media) &&
111
+ 'url' in uploadData.media &&
119
112
  !!uploadData.media.url &&
120
- !!options.mediaCache && (
121
- // generate the key
122
- mediaType + ':' + uploadData.media.url.toString());
113
+ !!options.mediaCache &&
114
+ mediaType + ':' + uploadData.media.url.toString();
123
115
  if (mediaType === 'document' && !uploadData.fileName) {
124
116
  uploadData.fileName = 'file';
125
117
  }
126
118
  if (!uploadData.mimetype) {
127
119
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
128
120
  }
129
- // check for cache hit
130
121
  if (cacheableKey) {
131
- const mediaBuff = options.mediaCache.get(cacheableKey);
122
+ const mediaBuff = await options.mediaCache.get(cacheableKey);
132
123
  if (mediaBuff) {
133
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
134
- const obj = Types_1.WAProto.Message.decode(mediaBuff);
124
+ logger?.debug({ cacheableKey }, 'got media cache hit');
125
+ const obj = proto.Message.decode(mediaBuff);
135
126
  const key = `${mediaType}Message`;
136
127
  Object.assign(obj[key], { ...uploadData, media: undefined });
137
128
  return obj;
138
129
  }
139
130
  }
131
+ const isNewsletter = !!options.jid && isJidNewsletter(options.jid);
132
+ if (isNewsletter) {
133
+ logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
134
+ const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
135
+ const fileSha256B64 = fileSha256.toString('base64');
136
+ const { mediaUrl, directPath } = await options.upload(filePath, {
137
+ fileEncSha256B64: fileSha256B64,
138
+ mediaType: mediaType,
139
+ timeoutMs: options.mediaUploadTimeoutMs
140
+ });
141
+ await fs.unlink(filePath);
142
+ const obj = WAProto.Message.fromObject({
143
+ // todo: add more support here
144
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
145
+ url: mediaUrl,
146
+ directPath,
147
+ fileSha256,
148
+ fileLength,
149
+ ...uploadData,
150
+ media: undefined
151
+ })
152
+ });
153
+ if (uploadData.ptv) {
154
+ obj.ptvMessage = obj.videoMessage;
155
+ delete obj.videoMessage;
156
+ }
157
+ if (obj.stickerMessage) {
158
+ obj.stickerMessage.stickerSentTs = Date.now();
159
+ }
160
+ if (cacheableKey) {
161
+ logger?.debug({ cacheableKey }, 'set cache');
162
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
163
+ }
164
+ return obj;
165
+ }
140
166
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
141
- const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
142
- (typeof uploadData['jpegThumbnail'] === 'undefined');
167
+ const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
143
168
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
144
169
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
145
170
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
146
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
171
+ const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
147
172
  logger,
148
173
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
149
174
  opts: options.options
150
175
  });
151
- // url safe Base64 encode the SHA256 hash of the body
152
- const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
153
- const [{ mediaUrl, directPath, handle }] = await Promise.all([
176
+ const fileEncSha256B64 = fileEncSha256.toString('base64');
177
+ const [{ mediaUrl, directPath }] = await Promise.all([
154
178
  (async () => {
155
- const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
156
- logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
179
+ const result = await options.upload(encFilePath, {
180
+ fileEncSha256B64,
181
+ mediaType,
182
+ timeoutMs: options.mediaUploadTimeoutMs
183
+ });
184
+ logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
157
185
  return result;
158
186
  })(),
159
187
  (async () => {
160
188
  try {
161
189
  if (requiresThumbnailComputation) {
162
- const { thumbnail, originalImageDimensions } = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
190
+ const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
163
191
  uploadData.jpegThumbnail = thumbnail;
164
192
  if (!uploadData.width && originalImageDimensions) {
165
193
  uploadData.width = originalImageDimensions.width;
166
194
  uploadData.height = originalImageDimensions.height;
167
- logger === null || logger === void 0 ? void 0 : logger.debug('set dimensions');
195
+ logger?.debug('set dimensions');
168
196
  }
169
- logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
197
+ logger?.debug('generated thumbnail');
170
198
  }
171
199
  if (requiresDurationComputation) {
172
- uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
173
- logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
174
- }
175
- if (requiresWaveformProcessing) {
176
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
177
- logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
200
+ uploadData.seconds = await getAudioDuration(originalFilePath);
201
+ logger?.debug('computed audio duration');
178
202
  }
179
203
  if (requiresWaveformProcessing) {
180
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
181
- logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
204
+ uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
205
+ logger?.debug('processed waveform');
182
206
  }
183
207
  if (requiresAudioBackground) {
184
208
  uploadData.backgroundArgb = await assertColor(options.backgroundColor);
185
- logger === null || logger === void 0 ? void 0 : logger.debug('computed backgroundColor audio status');
209
+ logger?.debug('computed backgroundColor audio status');
186
210
  }
187
211
  }
188
212
  catch (error) {
189
- logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
213
+ logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
190
214
  }
191
- })(),
192
- ])
193
- .finally(async () => {
194
- if (!Buffer.isBuffer(encWriteStream)) {
195
- encWriteStream.destroy();
215
+ })()
216
+ ]).finally(async () => {
217
+ try {
218
+ await fs.unlink(encFilePath);
219
+ if (originalFilePath) {
220
+ await fs.unlink(originalFilePath);
221
+ }
222
+ logger?.debug('removed tmp files');
196
223
  }
197
- // remove tmp files
198
- if (didSaveToTmpPath && bodyPath) {
199
- await fs_1.promises.unlink(bodyPath);
200
- logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
224
+ catch (error) {
225
+ logger?.warn('failed to remove tmp file');
201
226
  }
202
227
  });
203
- const obj = Types_1.WAProto.Message.fromObject({
228
+ const obj = WAProto.Message.fromObject({
204
229
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
205
- url: handle ? undefined : mediaUrl,
230
+ url: mediaUrl,
206
231
  directPath,
207
- mediaKey: mediaKey,
208
- fileEncSha256: fileEncSha256,
232
+ mediaKey,
233
+ fileEncSha256,
209
234
  fileSha256,
210
235
  fileLength,
211
- mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
236
+ mediaKeyTimestamp: unixTimestampSeconds(),
212
237
  ...uploadData,
213
238
  media: undefined
214
239
  })
@@ -218,70 +243,65 @@ const prepareWAMessageMedia = async (message, options) => {
218
243
  delete obj.videoMessage;
219
244
  }
220
245
  if (cacheableKey) {
221
- logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
222
- options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
246
+ logger?.debug({ cacheableKey }, 'set cache');
247
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
223
248
  }
224
249
  return obj;
225
250
  };
226
- exports.prepareWAMessageMedia = prepareWAMessageMedia;
227
- const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
251
+ export const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
228
252
  ephemeralExpiration = ephemeralExpiration || 0;
229
253
  const content = {
230
254
  ephemeralMessage: {
231
255
  message: {
232
256
  protocolMessage: {
233
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
257
+ type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
234
258
  ephemeralExpiration
235
259
  }
236
260
  }
237
261
  }
238
262
  };
239
- return Types_1.WAProto.Message.fromObject(content);
263
+ return WAProto.Message.fromObject(content);
240
264
  };
241
- exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
242
265
  /**
243
266
  * Generate forwarded message content like WA does
244
267
  * @param message the message to forward
245
268
  * @param options.forceForward will show the message as forwarded even if it is from you
246
269
  */
247
- const generateForwardMessageContent = (message, forceForward) => {
248
- var _a;
270
+ export const generateForwardMessageContent = (message, forceForward) => {
249
271
  let content = message.message;
250
272
  if (!content) {
251
- throw new boom_1.Boom('no content in message', { statusCode: 400 });
273
+ throw new Boom('no content in message', { statusCode: 400 });
252
274
  }
253
275
  // hacky copy
254
- content = (0, exports.normalizeMessageContent)(content);
255
- content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish());
276
+ content = normalizeMessageContent(content);
277
+ content = proto.Message.decode(proto.Message.encode(content).finish());
256
278
  let key = Object.keys(content)[0];
257
- let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
279
+ let score = content?.[key]?.contextInfo?.forwardingScore || 0;
258
280
  score += message.key.fromMe && !forceForward ? 0 : 1;
259
281
  if (key === 'conversation') {
260
282
  content.extendedTextMessage = { text: content[key] };
261
283
  delete content.conversation;
262
284
  key = 'extendedTextMessage';
263
285
  }
286
+ const key_ = content?.[key];
264
287
  if (score > 0) {
265
- content[key].contextInfo = { forwardingScore: score, isForwarded: true };
288
+ key_.contextInfo = { forwardingScore: score, isForwarded: true };
266
289
  }
267
290
  else {
268
- content[key].contextInfo = {};
291
+ key_.contextInfo = {};
269
292
  }
270
293
  return content;
271
294
  };
272
- exports.generateForwardMessageContent = generateForwardMessageContent;
273
- const generateWAMessageContent = async (message, options) => {
274
- var _a;
275
- var _b;
295
+ export const generateWAMessageContent = async (message, options) => {
296
+ var _a, _b;
276
297
  let m = {};
277
298
  if ('text' in message) {
278
299
  const extContent = { text: message.text };
279
300
  let urlInfo = message.linkPreview;
280
301
  if (typeof urlInfo === 'undefined') {
281
- urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
302
+ urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger);
282
303
  }
283
304
  if (urlInfo) {
284
- extContent.canonicalUrl = urlInfo['canonical-url'];
285
305
  extContent.matchedText = urlInfo['matched-text'];
286
306
  extContent.jpegThumbnail = urlInfo.jpegThumbnail;
287
307
  extContent.description = urlInfo.description;
@@ -309,38 +329,68 @@ const generateWAMessageContent = async (message, options) => {
309
329
  else if ('contacts' in message) {
310
330
  const contactLen = message.contacts.contacts.length;
311
331
  if (!contactLen) {
312
- throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
332
+ throw new Boom('require atleast 1 contact', { statusCode: 400 });
313
333
  }
314
334
  if (contactLen === 1) {
315
- m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0]);
335
+ m.contactMessage = WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
316
336
  }
317
337
  else {
318
- m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts);
338
+ m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts);
319
339
  }
320
340
  }
321
341
  else if ('location' in message) {
322
- m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
342
+ m.locationMessage = WAProto.Message.LocationMessage.create(message.location);
323
343
  }
324
344
  else if ('react' in message) {
325
345
  if (!message.react.senderTimestampMs) {
326
346
  message.react.senderTimestampMs = Date.now();
327
347
  }
328
- m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
348
+ m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react);
329
349
  }
330
350
  else if ('delete' in message) {
331
351
  m.protocolMessage = {
332
352
  key: message.delete,
333
- type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
353
+ type: WAProto.Message.ProtocolMessage.Type.REVOKE
334
354
  };
335
355
  }
336
356
  else if ('forward' in message) {
337
- m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
357
+ m = generateForwardMessageContent(message.forward, message.force);
338
358
  }
339
359
  else if ('disappearingMessagesInChat' in message) {
340
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
341
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
342
- message.disappearingMessagesInChat;
343
- m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
360
+ const exp = typeof message.disappearingMessagesInChat === 'boolean'
361
+ ? message.disappearingMessagesInChat
362
+ ? WA_DEFAULT_EPHEMERAL
363
+ : 0
364
+ : message.disappearingMessagesInChat;
365
+ m = prepareDisappearingMessageSettingContent(exp);
366
+ }
367
+ else if ('groupInvite' in message) {
368
+ m.groupInviteMessage = {};
369
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
370
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
371
+ m.groupInviteMessage.caption = message.groupInvite.text;
372
+ m.groupInviteMessage.groupJid = message.groupInvite.jid;
373
+ m.groupInviteMessage.groupName = message.groupInvite.subject;
374
+ //TODO: use built-in interface and get disappearing mode info etc.
375
+ //TODO: cache / use store!?
376
+ if (options.getProfilePicUrl) {
377
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
378
+ if (pfpUrl) {
379
+ const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
380
+ if (resp.ok) {
381
+ const buf = Buffer.from(await resp.arrayBuffer());
382
+ m.groupInviteMessage.jpegThumbnail = buf;
383
+ }
384
+ }
385
+ }
386
+ }
387
+ else if ('pin' in message) {
388
+ m.pinInChatMessage = {};
389
+ m.messageContextInfo = {};
390
+ m.pinInChatMessage.key = message.pin;
391
+ m.pinInChatMessage.type = message.type;
392
+ m.pinInChatMessage.senderTimestampMs = Date.now();
393
+ m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
344
394
  }
345
395
  else if ('buttonReply' in message) {
346
396
  switch (message.type) {
@@ -348,64 +398,115 @@ const generateWAMessageContent = async (message, options) => {
348
398
  m.templateButtonReplyMessage = {
349
399
  selectedDisplayText: message.buttonReply.displayText,
350
400
  selectedId: message.buttonReply.id,
351
- selectedIndex: message.buttonReply.index,
401
+ selectedIndex: message.buttonReply.index
352
402
  };
353
403
  break;
354
404
  case 'plain':
355
405
  m.buttonsResponseMessage = {
356
406
  selectedButtonId: message.buttonReply.id,
357
407
  selectedDisplayText: message.buttonReply.displayText,
358
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
408
+ type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
359
409
  };
360
410
  break;
361
411
  }
362
412
  }
413
+ else if ('ptv' in message && message.ptv) {
414
+ const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options);
415
+ m.ptvMessage = videoMessage;
416
+ }
363
417
  else if ('product' in message) {
364
- const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
365
- m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
418
+ const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options);
419
+ m.productMessage = WAProto.Message.ProductMessage.create({
366
420
  ...message,
367
421
  product: {
368
422
  ...message.product,
369
- productImage: imageMessage,
423
+ productImage: imageMessage
370
424
  }
371
425
  });
372
426
  }
373
427
  else if ('listReply' in message) {
374
428
  m.listResponseMessage = { ...message.listReply };
375
429
  }
430
+ else if ('event' in message) {
431
+ m.eventMessage = {};
432
+ const startTime = Math.floor(message.event.startDate.getTime() / 1000);
433
+ if (message.event.call && options.getCallLink) {
434
+ const token = await options.getCallLink(message.event.call, { startTime });
435
+ m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
436
+ }
437
+ m.messageContextInfo = {
438
+ // encKey
439
+ messageSecret: message.event.messageSecret || randomBytes(32)
440
+ };
441
+ m.eventMessage.name = message.event.name;
442
+ m.eventMessage.description = message.event.description;
443
+ m.eventMessage.startTime = startTime;
444
+ m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
445
+ m.eventMessage.isCanceled = message.event.isCancelled ?? false;
446
+ m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
447
+ m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
448
+ m.eventMessage.location = message.event.location;
449
+ }
376
450
  else if ('poll' in message) {
377
- (_b = message.poll).selectableCount || (_b.selectableCount = 0);
451
+ (_a = message.poll).selectableCount || (_a.selectableCount = 0);
452
+ (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
378
453
  if (!Array.isArray(message.poll.values)) {
379
- throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
454
+ throw new Boom('Invalid poll values', { statusCode: 400 });
380
455
  }
381
- if (message.poll.selectableCount < 0
382
- || message.poll.selectableCount > message.poll.values.length) {
383
- throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, { statusCode: 400 });
456
+ if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
457
+ throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
458
+ statusCode: 400
459
+ });
384
460
  }
385
461
  m.messageContextInfo = {
386
462
  // encKey
387
- messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
463
+ messageSecret: message.poll.messageSecret || randomBytes(32)
388
464
  };
389
- m.pollCreationMessage = {
465
+ const pollCreationMessage = {
390
466
  name: message.poll.name,
391
467
  selectableOptionsCount: message.poll.selectableCount,
392
- options: message.poll.values.map(optionName => ({ optionName })),
468
+ options: message.poll.values.map(optionName => ({ optionName }))
393
469
  };
470
+ if (message.poll.toAnnouncementGroup) {
471
+ // poll v2 is for community announcement groups (single select and multiple)
472
+ m.pollCreationMessageV2 = pollCreationMessage;
473
+ }
474
+ else {
475
+ if (message.poll.selectableCount === 1) {
476
+ //poll v3 is for single select polls
477
+ m.pollCreationMessageV3 = pollCreationMessage;
478
+ }
479
+ else {
480
+ // poll for multiple choice polls
481
+ m.pollCreationMessage = pollCreationMessage;
482
+ }
483
+ }
394
484
  }
395
485
  else if ('sharePhoneNumber' in message) {
396
486
  m.protocolMessage = {
397
- type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
487
+ type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
398
488
  };
399
489
  }
400
490
  else if ('requestPhoneNumber' in message) {
401
491
  m.requestPhoneNumberMessage = {};
402
492
  }
493
+ else if ('limitSharing' in message) {
494
+ m.protocolMessage = {
495
+ type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
496
+ limitSharing: {
497
+ sharingLimited: message.limitSharing === true,
498
+ trigger: 1,
499
+ limitSharingSettingTimestamp: Date.now(),
500
+ initiatedByMe: true
501
+ }
502
+ };
503
+ }
403
504
  else {
404
- m = await (0, exports.prepareWAMessageMedia)(message, options);
505
+ m = await prepareWAMessageMedia(message, options);
405
506
  }
406
507
  if ('buttons' in message && !!message.buttons) {
407
508
  const buttonsMessage = {
408
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
509
+ buttons: message.buttons.map(b => ({ ...b, type: proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
409
510
  };
410
511
  if ('text' in message) {
411
512
  buttonsMessage.contentText = message.text;
@@ -454,17 +555,24 @@ const generateWAMessageContent = async (message, options) => {
454
555
  title: message.title,
455
556
  footerText: message.footer,
456
557
  description: message.text,
457
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
558
+ listType: proto.Message.ListMessage.ListType.SINGLE_SELECT
458
559
  };
459
560
  m = { listMessage };
460
561
  }
461
562
  if ('viewOnce' in message && !!message.viewOnce) {
462
563
  m = { viewOnceMessage: { message: m } };
463
564
  }
464
- if ('mentions' in message && ((_a = message.mentions) === null || _a === void 0 ? void 0 : _a.length)) {
465
- const [messageType] = Object.keys(m);
466
- m[messageType].contextInfo = m[messageType] || {};
467
- m[messageType].contextInfo.mentionedJid = message.mentions;
565
+ if ('mentions' in message && message.mentions?.length) {
566
+ const messageType = Object.keys(m)[0];
567
+ const key = m[messageType];
568
+ if ('contextInfo' in key && !!key.contextInfo) {
569
+ key.contextInfo.mentionedJid = message.mentions;
570
+ }
571
+ else if (key) {
572
+ key.contextInfo = {
573
+ mentionedJid: message.mentions
574
+ };
575
+ }
468
576
  }
469
577
  if ('edit' in message) {
470
578
  m = {
@@ -472,40 +580,46 @@ const generateWAMessageContent = async (message, options) => {
472
580
  key: message.edit,
473
581
  editedMessage: m,
474
582
  timestampMs: Date.now(),
475
- type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
583
+ type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
476
584
  }
477
585
  };
478
586
  }
479
587
  if ('contextInfo' in message && !!message.contextInfo) {
480
- const [messageType] = Object.keys(m);
481
- m[messageType] = m[messageType] || {};
482
- m[messageType].contextInfo = message.contextInfo;
588
+ const messageType = Object.keys(m)[0];
589
+ const key = m[messageType];
590
+ if ('contextInfo' in key && !!key.contextInfo) {
591
+ key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
592
+ }
593
+ else if (key) {
594
+ key.contextInfo = message.contextInfo;
595
+ }
483
596
  }
484
- return Types_1.WAProto.Message.fromObject(m);
597
+ return WAProto.Message.create(m);
485
598
  };
486
- exports.generateWAMessageContent = generateWAMessageContent;
487
- const generateWAMessageFromContent = (jid, message, options) => {
599
+ export const generateWAMessageFromContent = (jid, message, options) => {
488
600
  // set timestamp to now
489
601
  // if not specified
490
602
  if (!options.timestamp) {
491
603
  options.timestamp = new Date();
492
604
  }
493
- const innerMessage = (0, exports.normalizeMessageContent)(message);
494
- const key = (0, exports.getContentType)(innerMessage);
495
- const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
605
+ const innerMessage = normalizeMessageContent(message);
606
+ const key = getContentType(innerMessage);
607
+ const timestamp = unixTimestampSeconds(options.timestamp);
496
608
  const { quoted, userJid } = options;
497
- if (quoted && !(0, WABinary_1.isJidNewsLetter)(jid)) {
498
- const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
499
- let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
500
- const msgType = (0, exports.getContentType)(quotedMsg);
609
+ if (quoted && !isJidNewsletter(jid)) {
610
+ const participant = quoted.key.fromMe
611
+ ? userJid // TODO: Add support for LIDs
612
+ : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
613
+ let quotedMsg = normalizeMessageContent(quoted.message);
614
+ const msgType = getContentType(quotedMsg);
501
615
  // strip any redundant properties
502
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
616
+ quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
503
617
  const quotedContent = quotedMsg[msgType];
504
618
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
505
619
  delete quotedContent.contextInfo;
506
620
  }
507
- const contextInfo = innerMessage[key].contextInfo || {};
508
- contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
621
+ const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
622
+ contextInfo.participant = jidNormalizedUser(participant);
509
623
  contextInfo.stanzaId = quoted.key.id;
510
624
  contextInfo.quotedMessage = quotedMsg;
511
625
  // if a participant is quoted, then it must be a group
@@ -513,62 +627,63 @@ const generateWAMessageFromContent = (jid, message, options) => {
513
627
  if (jid !== quoted.key.remoteJid) {
514
628
  contextInfo.remoteJid = quoted.key.remoteJid;
515
629
  }
516
- innerMessage[key].contextInfo = contextInfo;
630
+ if (contextInfo && innerMessage[key]) {
631
+ /* @ts-ignore */
632
+ innerMessage[key].contextInfo = contextInfo;
633
+ }
517
634
  }
518
635
  if (
519
636
  // if we want to send a disappearing message
520
- !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
637
+ !!options?.ephemeralExpiration &&
521
638
  // and it's not a protocol message -- delete, toggle disappear message
522
639
  key !== 'protocolMessage' &&
523
640
  // already not converted to disappearing message
524
641
  key !== 'ephemeralMessage' &&
525
- // newsletter not accept disappearing messages
526
- !(0, WABinary_1.isJidNewsLetter)(jid)) {
642
+ // newsletters don't support ephemeral messages
643
+ !isJidNewsletter(jid)) {
644
+ /* @ts-ignore */
527
645
  innerMessage[key].contextInfo = {
528
646
  ...(innerMessage[key].contextInfo || {}),
529
- expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
647
+ expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
530
648
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
531
649
  };
532
650
  }
533
- message = Types_1.WAProto.Message.fromObject(message);
651
+ message = WAProto.Message.create(message);
534
652
  const messageJSON = {
535
653
  key: {
536
654
  remoteJid: jid,
537
655
  fromMe: true,
538
- id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
656
+ id: options?.messageId || generateMessageIDV2()
539
657
  },
540
658
  message: message,
541
659
  messageTimestamp: timestamp,
542
660
  messageStubParameters: [],
543
- participant: (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid) ? userJid : undefined,
544
- status: Types_1.WAMessageStatus.PENDING
661
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
662
+ status: WAMessageStatus.PENDING
545
663
  };
546
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
664
+ return WAProto.WebMessageInfo.fromObject(messageJSON);
547
665
  };
548
- exports.generateWAMessageFromContent = generateWAMessageFromContent;
549
- const generateWAMessage = async (jid, content, options) => {
550
- var _a;
666
+ export const generateWAMessage = async (jid, content, options) => {
551
667
  // ensure msg ID is with every log
552
- options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
553
- return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsLetter)(jid), ...options }), options);
668
+ options.logger = options?.logger?.child({ msgId: options.messageId });
669
+ // Pass jid in the options to generateWAMessageContent
670
+ return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid }), options);
554
671
  };
555
- exports.generateWAMessage = generateWAMessage;
556
672
  /** Get the key to access the true type of content */
557
- const getContentType = (content) => {
673
+ export const getContentType = (content) => {
558
674
  if (content) {
559
675
  const keys = Object.keys(content);
560
676
  const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
561
677
  return key;
562
678
  }
563
679
  };
564
- exports.getContentType = getContentType;
565
680
  /**
566
681
  * Normalizes ephemeral, view once messages to regular message content
567
682
  * Eg. image messages in ephemeral messages, in view once messages etc.
568
683
  * @param content
569
684
  * @returns
570
685
  */
571
- const normalizeMessageContent = (content) => {
686
+ export const normalizeMessageContent = (content) => {
572
687
  if (!content) {
573
688
  return undefined;
574
689
  }
@@ -582,21 +697,19 @@ const normalizeMessageContent = (content) => {
582
697
  }
583
698
  return content;
584
699
  function getFutureProofMessage(message) {
585
- return ((message === null || message === void 0 ? void 0 : message.ephemeralMessage)
586
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessage)
587
- || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage)
588
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2)
589
- || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension)
590
- || (message === null || message === void 0 ? void 0 : message.editedMessage));
700
+ return (message?.ephemeralMessage ||
701
+ message?.viewOnceMessage ||
702
+ message?.documentWithCaptionMessage ||
703
+ message?.viewOnceMessageV2 ||
704
+ message?.viewOnceMessageV2Extension ||
705
+ message?.editedMessage);
591
706
  }
592
707
  };
593
- exports.normalizeMessageContent = normalizeMessageContent;
594
708
  /**
595
709
  * Extract the true message content from a message
596
710
  * Eg. extracts the inner message from a disappearing message/view once message
597
711
  */
598
- const extractMessageContent = (content) => {
599
- var _a, _b, _c, _d, _e, _f;
712
+ export const extractMessageContent = (content) => {
600
713
  const extractFromTemplateMessage = (msg) => {
601
714
  if (msg.imageMessage) {
602
715
  return { imageMessage: msg.imageMessage };
@@ -612,35 +725,39 @@ const extractMessageContent = (content) => {
612
725
  }
613
726
  else {
614
727
  return {
615
- conversation: 'contentText' in msg
616
- ? msg.contentText
617
- : ('hydratedContentText' in msg ? msg.hydratedContentText : '')
728
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
618
729
  };
619
730
  }
620
731
  };
621
- content = (0, exports.normalizeMessageContent)(content);
622
- if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
732
+ content = normalizeMessageContent(content);
733
+ if (content?.buttonsMessage) {
623
734
  return extractFromTemplateMessage(content.buttonsMessage);
624
735
  }
625
- if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
626
- return extractFromTemplateMessage((_b = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _b === void 0 ? void 0 : _b.hydratedFourRowTemplate);
736
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
737
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
627
738
  }
628
- if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
629
- return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedTemplate);
739
+ if (content?.templateMessage?.hydratedTemplate) {
740
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
630
741
  }
631
- if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
632
- return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.fourRowTemplate);
742
+ if (content?.templateMessage?.fourRowTemplate) {
743
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
633
744
  }
634
745
  return content;
635
746
  };
636
- exports.extractMessageContent = extractMessageContent;
637
747
  /**
638
748
  * Returns the device predicted by message ID
639
749
  */
640
- const getDevice = (id) => /^3A.{18}$/.test(id) ? 'ios' : /^3E.{20}$/.test(id) ? 'web' : /^(.{21}|.{32})$/.test(id) ? 'android' : /^.{18}$/.test(id) ? 'desktop' : 'unknown';
641
- exports.getDevice = getDevice;
750
+ export const getDevice = (id) => /^3A.{18}$/.test(id)
751
+ ? 'ios'
752
+ : /^3E.{20}$/.test(id)
753
+ ? 'web'
754
+ : /^(.{21}|.{32})$/.test(id)
755
+ ? 'android'
756
+ : /^(3F|.{18}$)/.test(id)
757
+ ? 'desktop'
758
+ : 'unknown';
642
759
  /** Upserts a receipt in the message */
643
- const updateMessageWithReceipt = (msg, receipt) => {
760
+ export const updateMessageWithReceipt = (msg, receipt) => {
644
761
  msg.userReceipt = msg.userReceipt || [];
645
762
  const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
646
763
  if (recp) {
@@ -650,41 +767,36 @@ const updateMessageWithReceipt = (msg, receipt) => {
650
767
  msg.userReceipt.push(receipt);
651
768
  }
652
769
  };
653
- exports.updateMessageWithReceipt = updateMessageWithReceipt;
654
770
  /** Update the message with a new reaction */
655
- const updateMessageWithReaction = (msg, reaction) => {
656
- const authorID = (0, generics_1.getKeyAuthor)(reaction.key);
657
- const reactions = (msg.reactions || [])
658
- .filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
659
- if (reaction.text) {
660
- reactions.push(reaction);
661
- }
771
+ export const updateMessageWithReaction = (msg, reaction) => {
772
+ const authorID = getKeyAuthor(reaction.key);
773
+ const reactions = (msg.reactions || []).filter(r => getKeyAuthor(r.key) !== authorID);
774
+ reaction.text = reaction.text || '';
775
+ reactions.push(reaction);
662
776
  msg.reactions = reactions;
663
777
  };
664
- exports.updateMessageWithReaction = updateMessageWithReaction;
665
778
  /** Update the message with a new poll update */
666
- const updateMessageWithPollUpdate = (msg, update) => {
667
- var _a, _b;
668
- const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey);
669
- const reactions = (msg.pollUpdates || [])
670
- .filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
671
- if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
779
+ export const updateMessageWithPollUpdate = (msg, update) => {
780
+ const authorID = getKeyAuthor(update.pollUpdateMessageKey);
781
+ const reactions = (msg.pollUpdates || []).filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID);
782
+ if (update.vote?.selectedOptions?.length) {
672
783
  reactions.push(update);
673
784
  }
674
785
  msg.pollUpdates = reactions;
675
786
  };
676
- exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
677
787
  /**
678
788
  * Aggregates all poll updates in a poll.
679
789
  * @param msg the poll creation message
680
790
  * @param meId your jid
681
791
  * @returns A list of options & their voters
682
792
  */
683
- function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
684
- var _a, _b, _c;
685
- 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) || [];
793
+ export function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
794
+ const opts = message?.pollCreationMessage?.options ||
795
+ message?.pollCreationMessageV2?.options ||
796
+ message?.pollCreationMessageV3?.options ||
797
+ [];
686
798
  const voteHashMap = opts.reduce((acc, opt) => {
687
- const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString();
799
+ const hash = sha256(Buffer.from(opt.optionName || '')).toString();
688
800
  acc[hash] = {
689
801
  name: opt.optionName || '',
690
802
  voters: []
@@ -706,14 +818,13 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
706
818
  };
707
819
  data = voteHashMap[hash];
708
820
  }
709
- voteHashMap[hash].voters.push((0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
821
+ voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId));
710
822
  }
711
823
  }
712
824
  return Object.values(voteHashMap);
713
825
  }
714
- exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
715
826
  /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
716
- const aggregateMessageKeysNotFromMe = (keys) => {
827
+ export const aggregateMessageKeysNotFromMe = (keys) => {
717
828
  const keyMap = {};
718
829
  for (const { remoteJid, id, participant, fromMe } of keys) {
719
830
  if (!fromMe) {
@@ -730,40 +841,34 @@ const aggregateMessageKeysNotFromMe = (keys) => {
730
841
  }
731
842
  return Object.values(keyMap);
732
843
  };
733
- exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
734
844
  const REUPLOAD_REQUIRED_STATUS = [410, 404];
735
845
  /**
736
846
  * Downloads the given message. Throws an error if it's not a media message
737
847
  */
738
- const downloadMediaMessage = async (message, type, options, ctx) => {
739
- const result = await downloadMsg()
740
- .catch(async (error) => {
741
- var _a;
742
- if (ctx) {
743
- if (axios_1.default.isAxiosError(error)) {
744
- // check if the message requires a reupload
745
- if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
746
- ctx.logger.info({ key: message.key }, 'sending reupload media request...');
747
- // request reupload
748
- message = await ctx.reuploadRequest(message);
749
- const result = await downloadMsg();
750
- return result;
751
- }
752
- }
848
+ export const downloadMediaMessage = async (message, type, options, ctx) => {
849
+ const result = await downloadMsg().catch(async (error) => {
850
+ if (ctx &&
851
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
852
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
853
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
854
+ // request reupload
855
+ message = await ctx.reuploadRequest(message);
856
+ const result = await downloadMsg();
857
+ return result;
753
858
  }
754
859
  throw error;
755
860
  });
756
861
  return result;
757
862
  async function downloadMsg() {
758
- const mContent = (0, exports.extractMessageContent)(message.message);
863
+ const mContent = extractMessageContent(message.message);
759
864
  if (!mContent) {
760
- throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
865
+ throw new Boom('No message present', { statusCode: 400, data: message });
761
866
  }
762
- const contentType = (0, exports.getContentType)(mContent);
763
- let mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
867
+ const contentType = getContentType(mContent);
868
+ let mediaType = contentType?.replace('Message', '');
764
869
  const media = mContent[contentType];
765
870
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
766
- throw new boom_1.Boom(`"${contentType}" message is not a media message`);
871
+ throw new Boom(`"${contentType}" message is not a media message`);
767
872
  }
768
873
  let download;
769
874
  if ('thumbnailDirectPath' in media && !('url' in media)) {
@@ -776,7 +881,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
776
881
  else {
777
882
  download = media;
778
883
  }
779
- const stream = await (0, messages_media_1.downloadContentFromMessage)(download, mediaType, options);
884
+ const stream = await downloadContentFromMessage(download, mediaType, options);
780
885
  if (type === 'buffer') {
781
886
  const bufferArray = [];
782
887
  for await (const chunk of stream) {
@@ -787,18 +892,16 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
787
892
  return stream;
788
893
  }
789
894
  };
790
- exports.downloadMediaMessage = downloadMediaMessage;
791
- /** Checks whether the given message is a media message; if it is returns the inner content */
792
- const assertMediaContent = (content) => {
793
- content = (0, exports.extractMessageContent)(content);
794
- const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
795
- || (content === null || content === void 0 ? void 0 : content.imageMessage)
796
- || (content === null || content === void 0 ? void 0 : content.videoMessage)
797
- || (content === null || content === void 0 ? void 0 : content.audioMessage)
798
- || (content === null || content === void 0 ? void 0 : content.stickerMessage);
895
+
896
+ export const assertMediaContent = (content) => {
897
+ content = extractMessageContent(content);
898
+ const mediaContent = content?.documentMessage ||
899
+ content?.imageMessage ||
900
+ content?.videoMessage ||
901
+ content?.audioMessage ||
902
+ content?.stickerMessage;
799
903
  if (!mediaContent) {
800
- throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
904
+ throw new Boom('given message is not a media message', { statusCode: 400, data: content });
801
905
  }
802
906
  return mediaContent;
803
- };
804
- exports.assertMediaContent = assertMediaContent;
907
+ };