socketon 0.31.0 → 1.51.16

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