@d0v3riz/baileys 6.7.4 → 6.7.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 (43) hide show
  1. package/README.md +5 -4
  2. package/lib/Defaults/index.js +3 -1
  3. package/lib/Socket/business.d.ts +8 -5
  4. package/lib/Socket/chats.d.ts +3 -8
  5. package/lib/Socket/chats.js +15 -1
  6. package/lib/Socket/groups.d.ts +9 -1
  7. package/lib/Socket/groups.js +12 -1
  8. package/lib/Socket/index.d.ts +8 -5
  9. package/lib/Socket/messages-recv.d.ts +8 -6
  10. package/lib/Socket/messages-recv.js +105 -12
  11. package/lib/Socket/messages-send.d.ts +5 -3
  12. package/lib/Socket/messages-send.js +83 -71
  13. package/lib/Socket/registration.d.ts +8 -5
  14. package/lib/Socket/socket.js +2 -2
  15. package/lib/Store/make-in-memory-store.js +5 -1
  16. package/lib/Types/Chat.d.ts +2 -0
  17. package/lib/Types/Events.d.ts +5 -1
  18. package/lib/Types/GroupMetadata.d.ts +1 -1
  19. package/lib/Types/Message.d.ts +27 -24
  20. package/lib/Types/Socket.d.ts +5 -0
  21. package/lib/Types/index.d.ts +7 -0
  22. package/lib/Utils/crypto.d.ts +1 -1
  23. package/lib/Utils/crypto.js +4 -2
  24. package/lib/Utils/decode-wa-message.d.ts +1 -0
  25. package/lib/Utils/decode-wa-message.js +16 -7
  26. package/lib/Utils/generics.d.ts +4 -9
  27. package/lib/Utils/generics.js +34 -8
  28. package/lib/Utils/history.d.ts +4 -0
  29. package/lib/Utils/history.js +3 -0
  30. package/lib/Utils/messages-media.js +8 -14
  31. package/lib/Utils/messages.js +48 -58
  32. package/lib/Utils/noise-handler.d.ts +1 -1
  33. package/lib/Utils/noise-handler.js +2 -2
  34. package/lib/Utils/process-message.d.ts +3 -2
  35. package/lib/Utils/process-message.js +47 -24
  36. package/lib/Utils/signal.js +26 -16
  37. package/lib/WABinary/decode.d.ts +2 -2
  38. package/lib/WABinary/decode.js +6 -4
  39. package/lib/WABinary/encode.d.ts +1 -1
  40. package/lib/WABinary/encode.js +8 -4
  41. package/lib/WABinary/jid-utils.d.ts +2 -0
  42. package/lib/WABinary/jid-utils.js +4 -1
  43. package/package.json +6 -5
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.decryptMessageNode = exports.decodeMessageNode = void 0;
3
+ exports.decryptMessageNode = exports.decodeMessageNode = exports.NO_MESSAGE_FOUND_ERROR_TEXT = void 0;
4
4
  const boom_1 = require("@hapi/boom");
5
5
  const WAProto_1 = require("../../WAProto");
6
6
  const WABinary_1 = require("../WABinary");
7
7
  const generics_1 = require("./generics");
8
- const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
8
+ exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
9
9
  /**
10
10
  * Decode the received node as a message.
11
11
  * @note this will only parse the message, not decrypt it
12
12
  */
13
13
  function decodeMessageNode(stanza, meId, meLid) {
14
+ var _a;
14
15
  let msgType;
15
16
  let chatId;
16
17
  let author;
@@ -68,11 +69,16 @@ function decodeMessageNode(stanza, meId, meLid) {
68
69
  chatId = from;
69
70
  author = participant;
70
71
  }
72
+ else if ((0, WABinary_1.isJidNewsletter)(from)) {
73
+ msgType = 'newsletter';
74
+ chatId = from;
75
+ author = from;
76
+ }
71
77
  else {
72
78
  throw new boom_1.Boom('Unknown message type', { data: stanza });
73
79
  }
74
80
  const fromMe = ((0, WABinary_1.isLidUser)(from) ? isMeLid : isMe)(stanza.attrs.participant || stanza.attrs.from);
75
- const pushname = stanza.attrs.notify;
81
+ const pushname = (_a = stanza === null || stanza === void 0 ? void 0 : stanza.attrs) === null || _a === void 0 ? void 0 : _a.notify;
76
82
  const key = {
77
83
  remoteJid: chatId,
78
84
  fromMe,
@@ -111,7 +117,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
111
117
  const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details);
112
118
  fullMessage.verifiedBizName = details.verifiedName;
113
119
  }
114
- if (tag !== 'enc') {
120
+ if (tag !== 'enc' && tag !== 'plaintext') {
115
121
  continue;
116
122
  }
117
123
  if (!(content instanceof Uint8Array)) {
@@ -120,7 +126,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
120
126
  decryptables += 1;
121
127
  let msgBuffer;
122
128
  try {
123
- const e2eType = attrs.type;
129
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type;
124
130
  switch (e2eType) {
125
131
  case 'skmsg':
126
132
  msgBuffer = await repository.decryptGroupMessage({
@@ -138,10 +144,13 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
138
144
  ciphertext: content
139
145
  });
140
146
  break;
147
+ case 'plaintext':
148
+ msgBuffer = content;
149
+ break;
141
150
  default:
142
151
  throw new Error(`Unknown e2e type: ${e2eType}`);
143
152
  }
144
- let msg = WAProto_1.proto.Message.decode((0, generics_1.unpadRandomMax16)(msgBuffer));
153
+ let msg = WAProto_1.proto.Message.decode(e2eType !== 'plaintext' ? (0, generics_1.unpadRandomMax16)(msgBuffer) : msgBuffer);
145
154
  msg = ((_a = msg.deviceSentMessage) === null || _a === void 0 ? void 0 : _a.message) || msg;
146
155
  if (msg.senderKeyDistributionMessage) {
147
156
  try {
@@ -171,7 +180,7 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
171
180
  // if nothing was found to decrypt
172
181
  if (!decryptables) {
173
182
  fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT;
174
- fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT, JSON.stringify(stanza, generics_1.BufferJSON.replacer)];
183
+ fullMessage.messageStubParameters = [exports.NO_MESSAGE_FOUND_ERROR_TEXT];
175
184
  }
176
185
  }
177
186
  };
@@ -2,16 +2,10 @@
2
2
  import { AxiosRequestConfig } from 'axios';
3
3
  import { Logger } from 'pino';
4
4
  import { proto } from '../../WAProto';
5
- import { BaileysEventEmitter, BaileysEventMap, WACallUpdateType, WAVersion } from '../Types';
5
+ import { BaileysEventEmitter, BaileysEventMap, BrowsersMap, WACallUpdateType, WAVersion } from '../Types';
6
6
  import { BinaryNode } from '../WABinary';
7
- export declare const Browsers: {
8
- ubuntu: (browser: any) => [string, string, string];
9
- macOS: (browser: any) => [string, string, string];
10
- baileys: (browser: any) => [string, string, string];
11
- windows: (browser: any) => [string, string, string];
12
- /** The appropriate browser based on your OS & release */
13
- appropriate: (browser: any) => [string, string, string];
14
- };
7
+ export declare const Browsers: BrowsersMap;
8
+ export declare const getPlatformId: (browser: string) => any;
15
9
  export declare const BufferJSON: {
16
10
  replacer: (k: any, value: any) => any;
17
11
  reviver: (_: any, value: any) => any;
@@ -38,6 +32,7 @@ export declare const delayCancellable: (ms: number) => {
38
32
  cancel: () => void;
39
33
  };
40
34
  export declare function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v: T) => void, reject: (error: any) => void) => void): Promise<T>;
35
+ export declare const generateMessageIDV2: (userId?: string) => string;
41
36
  export declare const generateMessageID: () => string;
42
37
  export declare function bindWaitForEvent<T extends keyof BaileysEventMap>(ev: BaileysEventEmitter, event: T): (check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => Promise<void>;
43
38
  export declare const bindWaitForConnectionUpdate: (ev: BaileysEventEmitter) => (check: (u: Partial<import("../Types").ConnectionState>) => boolean | undefined, timeoutMs?: number) => Promise<void>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.Browsers = void 0;
6
+ exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.generateMessageIDV2 = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const crypto_1 = require("crypto");
@@ -16,16 +16,24 @@ const PLATFORM_MAP = {
16
16
  'aix': 'AIX',
17
17
  'darwin': 'Mac OS',
18
18
  'win32': 'Windows',
19
- 'android': 'Android'
19
+ 'android': 'Android',
20
+ 'freebsd': 'FreeBSD',
21
+ 'openbsd': 'OpenBSD',
22
+ 'sunos': 'Solaris'
20
23
  };
21
24
  exports.Browsers = {
22
- ubuntu: browser => ['Ubuntu', browser, '20.0.04'],
23
- macOS: browser => ['Mac OS', browser, '10.15.7'],
24
- baileys: browser => ['Baileys', browser, '4.0.0'],
25
- windows: browser => ['Windows', browser, '10.0.22621'],
25
+ ubuntu: (browser) => ['Ubuntu', browser, '22.04.4'],
26
+ macOS: (browser) => ['Mac OS', browser, '14.4.1'],
27
+ baileys: (browser) => ['Baileys', browser, '6.5.0'],
28
+ windows: (browser) => ['Windows', browser, '10.0.22631'],
26
29
  /** The appropriate browser based on your OS & release */
27
- appropriate: browser => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
30
+ appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
28
31
  };
32
+ const getPlatformId = (browser) => {
33
+ const platformType = WAProto_1.proto.DeviceProps.PlatformType[browser.toUpperCase()];
34
+ return platformType ? platformType.toString().charCodeAt(0).toString() : '49'; //chrome
35
+ };
36
+ exports.getPlatformId = getPlatformId;
29
37
  exports.BufferJSON = {
30
38
  replacer: (k, value) => {
31
39
  if (Buffer.isBuffer(value) || value instanceof Uint8Array || (value === null || value === void 0 ? void 0 : value.type) === 'Buffer') {
@@ -147,8 +155,26 @@ async function promiseTimeout(ms, promise) {
147
155
  return p;
148
156
  }
149
157
  exports.promiseTimeout = promiseTimeout;
158
+ // inspired from whatsmeow code
159
+ // https://github.com/tulir/whatsmeow/blob/64bc969fbe78d31ae0dd443b8d4c80a5d026d07a/send.go#L42
160
+ const generateMessageIDV2 = (userId) => {
161
+ const data = Buffer.alloc(8 + 20 + 16);
162
+ data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
163
+ if (userId) {
164
+ const id = (0, WABinary_1.jidDecode)(userId);
165
+ if (id === null || id === void 0 ? void 0 : id.user) {
166
+ data.write(id.user, 8);
167
+ data.write('@c.us', 8 + id.user.length);
168
+ }
169
+ }
170
+ const random = (0, crypto_1.randomBytes)(16);
171
+ random.copy(data, 28);
172
+ const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
173
+ return (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + hash.toString('hex').toUpperCase().substring(0, 18);
174
+ };
175
+ exports.generateMessageIDV2 = generateMessageIDV2;
150
176
  // generate a random ID to attach to a message
151
- const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(6).toString('hex').toUpperCase();
177
+ const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
152
178
  exports.generateMessageID = generateMessageID;
153
179
  function bindWaitForEvent(ev, event) {
154
180
  return async (check, timeoutMs) => {
@@ -6,10 +6,14 @@ export declare const processHistoryMessage: (item: proto.IHistorySync) => {
6
6
  chats: Chat[];
7
7
  contacts: Contact[];
8
8
  messages: proto.IWebMessageInfo[];
9
+ syncType: proto.HistorySync.HistorySyncType;
10
+ progress: number | null | undefined;
9
11
  };
10
12
  export declare const downloadAndProcessHistorySyncNotification: (msg: proto.Message.IHistorySyncNotification, options: AxiosRequestConfig<any>) => Promise<{
11
13
  chats: Chat[];
12
14
  contacts: Contact[];
13
15
  messages: proto.IWebMessageInfo[];
16
+ syncType: proto.HistorySync.HistorySyncType;
17
+ progress: number | null | undefined;
14
18
  }>;
15
19
  export declare const getHistoryMsg: (message: proto.IMessage) => proto.Message.IHistorySyncNotification | null | undefined;
@@ -32,6 +32,7 @@ const processHistoryMessage = (item) => {
32
32
  case WAProto_1.proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP:
33
33
  case WAProto_1.proto.HistorySync.HistorySyncType.RECENT:
34
34
  case WAProto_1.proto.HistorySync.HistorySyncType.FULL:
35
+ case WAProto_1.proto.HistorySync.HistorySyncType.ON_DEMAND:
35
36
  for (const chat of item.conversations) {
36
37
  contacts.push({ id: chat.id, name: chat.name || undefined });
37
38
  const msgs = chat.messages || [];
@@ -74,6 +75,8 @@ const processHistoryMessage = (item) => {
74
75
  chats,
75
76
  contacts,
76
77
  messages,
78
+ syncType: item.syncType,
79
+ progress: item.progress,
77
80
  };
78
81
  };
79
82
  exports.processHistoryMessage = processHistoryMessage;
@@ -22,9 +22,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
29
  exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.getHttpStream = exports.generateThumbnail = exports.getStream = exports.toBuffer = exports.toReadable = exports.getAudioWaveform = exports.getAudioDuration = exports.mediaMessageSHA256B64 = exports.generateProfilePicture = exports.encodeBase64EncodedStringForUpload = exports.extractImageThumb = exports.getMediaKeys = exports.hkdfInfoKey = void 0;
27
30
  const boom_1 = require("@hapi/boom");
31
+ const axios_1 = __importDefault(require("axios"));
28
32
  const child_process_1 = require("child_process");
29
33
  const Crypto = __importStar(require("crypto"));
30
34
  const events_1 = require("events");
@@ -313,8 +317,7 @@ async function generateThumbnail(file, mediaType, options) {
313
317
  }
314
318
  exports.generateThumbnail = generateThumbnail;
315
319
  const getHttpStream = async (url, options = {}) => {
316
- const { default: axios } = await import('axios');
317
- const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
320
+ const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
318
321
  return fetched.data;
319
322
  };
320
323
  exports.getHttpStream = getHttpStream;
@@ -525,27 +528,18 @@ exports.extensionForMediaMessage = extensionForMediaMessage;
525
528
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
526
529
  return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
527
530
  var _a, _b;
528
- const { default: axios } = await import('axios');
529
531
  // send a query JSON to obtain the url & auth token to upload our media
530
532
  let uploadInfo = await refreshMediaConn(false);
531
533
  let urls;
532
534
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
533
- const chunks = [];
534
- for await (const chunk of stream) {
535
- chunks.push(chunk);
536
- }
537
- const reqBody = Buffer.concat(chunks);
538
535
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
539
- for (const { hostname, maxContentLengthBytes } of hosts) {
536
+ for (const { hostname } of hosts) {
540
537
  logger.debug(`uploading to "${hostname}"`);
541
538
  const auth = encodeURIComponent(uploadInfo.auth); // the auth token
542
539
  const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
543
540
  let result;
544
541
  try {
545
- if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
546
- throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
547
- }
548
- const body = await axios.post(url, reqBody, {
542
+ const body = await axios_1.default.post(url, stream, {
549
543
  ...options,
550
544
  headers: {
551
545
  ...options.headers || {},
@@ -572,7 +566,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
572
566
  }
573
567
  }
574
568
  catch (error) {
575
- if (axios.isAxiosError(error)) {
569
+ if (axios_1.default.isAxiosError(error)) {
576
570
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
577
571
  }
578
572
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -30,7 +30,6 @@ const MessageTypeProto = {
30
30
  'sticker': Types_1.WAProto.Message.StickerMessage,
31
31
  'document': Types_1.WAProto.Message.DocumentMessage,
32
32
  };
33
- const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
34
33
  /**
35
34
  * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
36
35
  * @param text eg. hello https://google.com
@@ -238,7 +237,7 @@ const generateForwardMessageContent = (message, forceForward) => {
238
237
  exports.generateForwardMessageContent = generateForwardMessageContent;
239
238
  const generateWAMessageContent = async (message, options) => {
240
239
  var _a;
241
- var _b;
240
+ var _b, _c;
242
241
  let m = {};
243
242
  if ('text' in message) {
244
243
  const extContent = { text: message.text };
@@ -308,6 +307,33 @@ const generateWAMessageContent = async (message, options) => {
308
307
  message.disappearingMessagesInChat;
309
308
  m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
310
309
  }
310
+ else if ('groupInvite' in message) {
311
+ m.groupInviteMessage = {};
312
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
313
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
314
+ m.groupInviteMessage.caption = message.groupInvite.text;
315
+ m.groupInviteMessage.groupJid = message.groupInvite.jid;
316
+ m.groupInviteMessage.groupName = message.groupInvite.subject;
317
+ //TODO: use built-in interface and get disappearing mode info etc.
318
+ //TODO: cache / use store!?
319
+ if (options.getProfilePicUrl) {
320
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
321
+ if (pfpUrl) {
322
+ const resp = await axios_1.default.get(pfpUrl, { responseType: 'arraybuffer' });
323
+ if (resp.status === 200) {
324
+ m.groupInviteMessage.jpegThumbnail = resp.data;
325
+ }
326
+ }
327
+ }
328
+ }
329
+ else if ('pin' in message) {
330
+ m.pinInChatMessage = {};
331
+ m.messageContextInfo = {};
332
+ m.pinInChatMessage.key = message.pin;
333
+ m.pinInChatMessage.type = message.type;
334
+ m.pinInChatMessage.senderTimestampMs = Date.now();
335
+ m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
336
+ }
311
337
  else if ('buttonReply' in message) {
312
338
  switch (message.type) {
313
339
  case 'template':
@@ -326,6 +352,10 @@ const generateWAMessageContent = async (message, options) => {
326
352
  break;
327
353
  }
328
354
  }
355
+ else if ('ptv' in message && message.ptv) {
356
+ const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
357
+ m.ptvMessage = videoMessage;
358
+ }
329
359
  else if ('product' in message) {
330
360
  const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
331
361
  m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
@@ -341,6 +371,7 @@ const generateWAMessageContent = async (message, options) => {
341
371
  }
342
372
  else if ('poll' in message) {
343
373
  (_b = message.poll).selectableCount || (_b.selectableCount = 0);
374
+ (_c = message.poll).toAnnouncementGroup || (_c.toAnnouncementGroup = false);
344
375
  if (!Array.isArray(message.poll.values)) {
345
376
  throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
346
377
  }
@@ -352,11 +383,25 @@ const generateWAMessageContent = async (message, options) => {
352
383
  // encKey
353
384
  messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32),
354
385
  };
355
- m.pollCreationMessage = {
386
+ const pollCreationMessage = {
356
387
  name: message.poll.name,
357
388
  selectableOptionsCount: message.poll.selectableCount,
358
389
  options: message.poll.values.map(optionName => ({ optionName })),
359
390
  };
391
+ if (message.poll.toAnnouncementGroup) {
392
+ // poll v2 is for community announcement groups (single select and multiple)
393
+ m.pollCreationMessageV2 = pollCreationMessage;
394
+ }
395
+ else {
396
+ if (message.poll.selectableCount > 0) {
397
+ //poll v3 is for single select polls
398
+ m.pollCreationMessageV3 = pollCreationMessage;
399
+ }
400
+ else {
401
+ // poll v3 for multiple choice polls
402
+ m.pollCreationMessage = pollCreationMessage;
403
+ }
404
+ }
360
405
  }
361
406
  else if ('sharePhoneNumber' in message) {
362
407
  m.protocolMessage = {
@@ -369,61 +414,6 @@ const generateWAMessageContent = async (message, options) => {
369
414
  else {
370
415
  m = await (0, exports.prepareWAMessageMedia)(message, options);
371
416
  }
372
- if ('buttons' in message && !!message.buttons) {
373
- const buttonsMessage = {
374
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
375
- };
376
- if ('text' in message) {
377
- buttonsMessage.contentText = message.text;
378
- buttonsMessage.headerType = ButtonType.EMPTY;
379
- }
380
- else {
381
- if ('caption' in message) {
382
- buttonsMessage.contentText = message.caption;
383
- }
384
- const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
385
- buttonsMessage.headerType = ButtonType[type];
386
- Object.assign(buttonsMessage, m);
387
- }
388
- if ('footer' in message && !!message.footer) {
389
- buttonsMessage.footerText = message.footer;
390
- }
391
- m = { buttonsMessage };
392
- }
393
- else if ('templateButtons' in message && !!message.templateButtons) {
394
- const msg = {
395
- hydratedButtons: message.templateButtons
396
- };
397
- if ('text' in message) {
398
- msg.hydratedContentText = message.text;
399
- }
400
- else {
401
- if ('caption' in message) {
402
- msg.hydratedContentText = message.caption;
403
- }
404
- Object.assign(msg, m);
405
- }
406
- if ('footer' in message && !!message.footer) {
407
- msg.hydratedFooterText = message.footer;
408
- }
409
- m = {
410
- templateMessage: {
411
- fourRowTemplate: msg,
412
- hydratedTemplate: msg
413
- }
414
- };
415
- }
416
- if ('sections' in message && !!message.sections) {
417
- const listMessage = {
418
- sections: message.sections,
419
- buttonText: message.buttonText,
420
- title: message.title,
421
- footerText: message.footer,
422
- description: message.text,
423
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
424
- };
425
- m = { listMessage };
426
- }
427
417
  if ('viewOnce' in message && !!message.viewOnce) {
428
418
  m = { viewOnceMessage: { message: m } };
429
419
  }
@@ -17,5 +17,5 @@ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public
17
17
  finishInit: () => void;
18
18
  processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => Buffer;
19
19
  encodeFrame: (data: Buffer | Uint8Array) => Buffer;
20
- decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => void;
20
+ decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => Promise<void>;
21
21
  };
@@ -125,7 +125,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
125
125
  frame.set(data, introSize + 3);
126
126
  return frame;
127
127
  },
128
- decodeFrame: (newData, onFrame) => {
128
+ decodeFrame: async (newData, onFrame) => {
129
129
  var _a;
130
130
  // the binary protocol uses its own framing mechanism
131
131
  // on top of the WS frames
@@ -143,7 +143,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
143
143
  inBytes = inBytes.slice(size + 3);
144
144
  if (isFinished) {
145
145
  const result = decrypt(frame);
146
- frame = (0, WABinary_1.decodeBinaryNode)(result);
146
+ frame = await (0, WABinary_1.decodeBinaryNode)(result);
147
147
  }
148
148
  logger.trace({ msg: (_a = frame === null || frame === void 0 ? void 0 : frame.attrs) === null || _a === void 0 ? void 0 : _a.id }, 'recv frame');
149
149
  onFrame(frame);
@@ -1,9 +1,10 @@
1
1
  import { AxiosRequestConfig } from 'axios';
2
2
  import type { Logger } from 'pino';
3
3
  import { proto } from '../../WAProto';
4
- import { AuthenticationCreds, BaileysEventEmitter, SignalKeyStoreWithTransaction, SocketConfig } from '../Types';
4
+ import { AuthenticationCreds, BaileysEventEmitter, CacheStore, SignalKeyStoreWithTransaction, SocketConfig } from '../Types';
5
5
  type ProcessMessageContext = {
6
6
  shouldProcessHistoryMsg: boolean;
7
+ placeholderResendCache?: CacheStore;
7
8
  creds: AuthenticationCreds;
8
9
  keyStore: SignalKeyStoreWithTransaction;
9
10
  ev: BaileysEventEmitter;
@@ -37,5 +38,5 @@ type PollContext = {
37
38
  * @returns list of SHA256 options
38
39
  */
39
40
  export declare function decryptPollVote({ encPayload, encIv }: proto.Message.IPollEncValue, { pollCreatorJid, pollMsgId, pollEncKey, voterJid, }: PollContext): proto.Message.PollVoteMessage;
40
- declare const processMessage: (message: proto.IWebMessageInfo, { shouldProcessHistoryMsg, ev, creds, keyStore, logger, options, getMessage }: ProcessMessageContext) => Promise<void>;
41
+ declare const processMessage: (message: proto.IWebMessageInfo, { shouldProcessHistoryMsg, placeholderResendCache, ev, creds, keyStore, logger, options, getMessage }: ProcessMessageContext) => Promise<void>;
41
42
  export default processMessage;
@@ -102,8 +102,8 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
102
102
  }
103
103
  }
104
104
  exports.decryptPollVote = decryptPollVote;
105
- const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, keyStore, logger, options, getMessage }) => {
106
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
105
+ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderResendCache, ev, creds, keyStore, logger, options, getMessage }) => {
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
107
107
  const meId = creds.me.id;
108
108
  const { accountSettings } = creds;
109
109
  const chat = { id: (0, WABinary_1.jidNormalizedUser)((0, exports.getChatId)(message.key)) };
@@ -137,14 +137,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
137
137
  isLatest,
138
138
  }, 'got history notification');
139
139
  if (process) {
140
- ev.emit('creds.update', {
141
- processedHistoryMessages: [
142
- ...(creds.processedHistoryMessages || []),
143
- { key: message.key, messageTimestamp: message.messageTimestamp }
144
- ]
145
- });
140
+ if (histNotification.syncType !== WAProto_1.proto.HistorySync.HistorySyncType.ON_DEMAND) {
141
+ ev.emit('creds.update', {
142
+ processedHistoryMessages: [
143
+ ...(creds.processedHistoryMessages || []),
144
+ { key: message.key, messageTimestamp: message.messageTimestamp }
145
+ ]
146
+ });
147
+ }
146
148
  const data = await (0, history_1.downloadAndProcessHistorySyncNotification)(histNotification, options);
147
- ev.emit('messaging-history.set', { ...data, isLatest });
149
+ ev.emit('messaging-history.set', {
150
+ ...data,
151
+ isLatest: histNotification.syncType !== WAProto_1.proto.HistorySync.HistorySyncType.ON_DEMAND
152
+ ? isLatest
153
+ : undefined
154
+ });
148
155
  }
149
156
  break;
150
157
  case WAProto_1.proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
@@ -187,14 +194,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
187
194
  case WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
188
195
  const response = protocolMsg.peerDataOperationRequestResponseMessage;
189
196
  if (response) {
197
+ placeholderResendCache === null || placeholderResendCache === void 0 ? void 0 : placeholderResendCache.del(response.stanzaId);
198
+ // TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
190
199
  const { peerDataOperationResult } = response;
191
200
  for (const result of peerDataOperationResult) {
192
201
  const { placeholderMessageResendResponse: retryResponse } = result;
193
202
  if (retryResponse) {
194
203
  const webMessageInfo = WAProto_1.proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes);
195
- ev.emit('messages.update', [
196
- { key: webMessageInfo.key, update: { message: webMessageInfo.message } }
197
- ]);
204
+ // wait till another upsert event is available, don't want it to be part of the PDO response message
205
+ setTimeout(() => {
206
+ ev.emit('messages.upsert', {
207
+ messages: [webMessageInfo],
208
+ type: 'notify',
209
+ requestId: response.stanzaId
210
+ });
211
+ }, 500);
198
212
  }
199
213
  }
200
214
  }
@@ -208,11 +222,11 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
208
222
  };
209
223
  ev.emit('messages.reaction', [{
210
224
  reaction,
211
- key: content.reactionMessage.key,
225
+ key: (_d = content.reactionMessage) === null || _d === void 0 ? void 0 : _d.key,
212
226
  }]);
213
227
  }
214
228
  else if (message.messageStubType) {
215
- const jid = message.key.remoteJid;
229
+ const jid = (_e = message.key) === null || _e === void 0 ? void 0 : _e.remoteJid;
216
230
  //let actor = whatsappID (message.participant)
217
231
  let participants;
218
232
  const emitParticipantsUpdate = (action) => (ev.emit('group-participants.update', { id: jid, author: message.participant, participants, action }));
@@ -225,6 +239,10 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
225
239
  };
226
240
  const participantsIncludesMe = () => participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid));
227
241
  switch (message.messageStubType) {
242
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
243
+ participants = message.messageStubParameters || [];
244
+ emitParticipantsUpdate('modify');
245
+ break;
228
246
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
229
247
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
230
248
  participants = message.messageStubParameters || [];
@@ -252,34 +270,39 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
252
270
  emitParticipantsUpdate('promote');
253
271
  break;
254
272
  case Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
255
- const announceValue = (_d = message.messageStubParameters) === null || _d === void 0 ? void 0 : _d[0];
273
+ const announceValue = (_f = message.messageStubParameters) === null || _f === void 0 ? void 0 : _f[0];
256
274
  emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' });
257
275
  break;
258
276
  case Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT:
259
- const restrictValue = (_e = message.messageStubParameters) === null || _e === void 0 ? void 0 : _e[0];
277
+ const restrictValue = (_g = message.messageStubParameters) === null || _g === void 0 ? void 0 : _g[0];
260
278
  emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' });
261
279
  break;
262
280
  case Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT:
263
- const name = (_f = message.messageStubParameters) === null || _f === void 0 ? void 0 : _f[0];
281
+ const name = (_h = message.messageStubParameters) === null || _h === void 0 ? void 0 : _h[0];
264
282
  chat.name = name;
265
283
  emitGroupUpdate({ subject: name });
266
284
  break;
285
+ case Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION:
286
+ const description = (_j = message.messageStubParameters) === null || _j === void 0 ? void 0 : _j[0];
287
+ chat.description = description;
288
+ emitGroupUpdate({ desc: description });
289
+ break;
267
290
  case Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
268
- const code = (_g = message.messageStubParameters) === null || _g === void 0 ? void 0 : _g[0];
291
+ const code = (_k = message.messageStubParameters) === null || _k === void 0 ? void 0 : _k[0];
269
292
  emitGroupUpdate({ inviteCode: code });
270
293
  break;
271
294
  case Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE:
272
- const memberAddValue = (_h = message.messageStubParameters) === null || _h === void 0 ? void 0 : _h[0];
295
+ const memberAddValue = (_l = message.messageStubParameters) === null || _l === void 0 ? void 0 : _l[0];
273
296
  emitGroupUpdate({ memberAddMode: memberAddValue === 'all_member_add' });
274
297
  break;
275
298
  case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE:
276
- const approvalMode = (_j = message.messageStubParameters) === null || _j === void 0 ? void 0 : _j[0];
299
+ const approvalMode = (_m = message.messageStubParameters) === null || _m === void 0 ? void 0 : _m[0];
277
300
  emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' });
278
301
  break;
279
302
  case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
280
- const participant = (_k = message.messageStubParameters) === null || _k === void 0 ? void 0 : _k[0];
281
- const action = (_l = message.messageStubParameters) === null || _l === void 0 ? void 0 : _l[1];
282
- const method = (_m = message.messageStubParameters) === null || _m === void 0 ? void 0 : _m[2];
303
+ const participant = (_o = message.messageStubParameters) === null || _o === void 0 ? void 0 : _o[0];
304
+ const action = (_p = message.messageStubParameters) === null || _p === void 0 ? void 0 : _p[1];
305
+ const method = (_q = message.messageStubParameters) === null || _q === void 0 ? void 0 : _q[2];
283
306
  emitGroupRequestJoin(participant, action, method);
284
307
  break;
285
308
  }
@@ -292,7 +315,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
292
315
  const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId);
293
316
  const pollCreatorJid = (0, generics_1.getKeyAuthor)(creationMsgKey, meIdNormalised);
294
317
  const voterJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised);
295
- const pollEncKey = (_o = pollMsg.messageContextInfo) === null || _o === void 0 ? void 0 : _o.messageSecret;
318
+ const pollEncKey = (_r = pollMsg.messageContextInfo) === null || _r === void 0 ? void 0 : _r.messageSecret;
296
319
  try {
297
320
  const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
298
321
  pollEncKey,