@queenanya/baileys 7.1.3 → 7.1.7

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 (39) hide show
  1. package/README.md +56 -14
  2. package/lib/Defaults/index.js +5 -4
  3. package/lib/Socket/business.d.ts +31 -3
  4. package/lib/Socket/chats.d.ts +7 -0
  5. package/lib/Socket/chats.js +25 -0
  6. package/lib/Socket/groups.d.ts +15 -2
  7. package/lib/Socket/groups.js +11 -1
  8. package/lib/Socket/index.d.ts +31 -3
  9. package/lib/Socket/messages-recv.d.ts +32 -4
  10. package/lib/Socket/messages-recv.js +67 -4
  11. package/lib/Socket/messages-send.d.ts +29 -1
  12. package/lib/Socket/messages-send.js +61 -9
  13. package/lib/Socket/newsletter.d.ts +140 -0
  14. package/lib/Socket/newsletter.js +249 -0
  15. package/lib/Socket/registration.d.ts +31 -3
  16. package/lib/Socket/socket.js +2 -1
  17. package/lib/Types/Chat.d.ts +3 -0
  18. package/lib/Types/Events.d.ts +27 -0
  19. package/lib/Types/Label.d.ts +11 -0
  20. package/lib/Types/Message.d.ts +25 -3
  21. package/lib/Types/Newsletter.d.ts +79 -0
  22. package/lib/Types/Newsletter.js +18 -0
  23. package/lib/Types/Socket.d.ts +2 -0
  24. package/lib/Types/index.d.ts +2 -0
  25. package/lib/Types/index.js +1 -0
  26. package/lib/Utils/chat-utils.js +16 -0
  27. package/lib/Utils/decode-wa-message.js +46 -18
  28. package/lib/Utils/generics.d.ts +12 -0
  29. package/lib/Utils/generics.js +26 -6
  30. package/lib/Utils/messages-media.d.ts +10 -1
  31. package/lib/Utils/messages-media.js +53 -4
  32. package/lib/Utils/messages.js +51 -11
  33. package/lib/Utils/process-message.js +13 -8
  34. package/lib/Utils/signal.js +0 -5
  35. package/lib/WABinary/encode.d.ts +1 -2
  36. package/lib/WABinary/encode.js +3 -7
  37. package/lib/WABinary/jid-utils.d.ts +3 -1
  38. package/lib/WABinary/jid-utils.js +4 -1
  39. package/package.json +10 -8
@@ -11,6 +11,7 @@ const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
11
11
  * @note this will only parse the message, not decrypt it
12
12
  */
13
13
  function decodeMessageNode(stanza, meId, meLid) {
14
+ var _a, _b, _c, _d;
14
15
  let msgType;
15
16
  let chatId;
16
17
  let author;
@@ -54,6 +55,11 @@ function decodeMessageNode(stanza, meId, meLid) {
54
55
  author = participant;
55
56
  chatId = from;
56
57
  }
58
+ else if ((0, WABinary_1.isJidNewsletter)(from)) {
59
+ msgType = 'newsletter';
60
+ author = from;
61
+ chatId = from;
62
+ }
57
63
  else if ((0, WABinary_1.isJidBroadcast)(from)) {
58
64
  if (!participant) {
59
65
  throw new boom_1.Boom('No participant in group message');
@@ -68,16 +74,22 @@ function decodeMessageNode(stanza, meId, meLid) {
68
74
  chatId = from;
69
75
  author = participant;
70
76
  }
77
+ else if ((0, WABinary_1.isJidNewsletter)(from)) {
78
+ msgType = 'newsletter';
79
+ author = from;
80
+ chatId = from;
81
+ }
71
82
  else {
72
83
  throw new boom_1.Boom('Unknown message type', { data: stanza });
73
84
  }
74
- const fromMe = ((0, WABinary_1.isLidUser)(from) ? isMeLid : isMe)(stanza.attrs.participant || stanza.attrs.from);
75
- const pushname = stanza.attrs.notify;
85
+ const fromMe = (0, WABinary_1.isJidNewsletter)(from) ? !!((_a = stanza.attrs) === null || _a === void 0 ? void 0 : _a.is_sender) || false : ((0, WABinary_1.isLidUser)(from) ? isMeLid : isMe)(stanza.attrs.participant || stanza.attrs.from);
86
+ const pushname = (_b = stanza === null || stanza === void 0 ? void 0 : stanza.attrs) === null || _b === void 0 ? void 0 : _b.notify;
76
87
  const key = {
77
88
  remoteJid: chatId,
78
89
  fromMe,
79
90
  id: msgId,
80
- participant
91
+ participant,
92
+ server_id: (_c = stanza.attrs) === null || _c === void 0 ? void 0 : _c.server_id
81
93
  };
82
94
  const fullMessage = {
83
95
  key,
@@ -85,6 +97,9 @@ function decodeMessageNode(stanza, meId, meLid) {
85
97
  pushName: pushname,
86
98
  broadcast: (0, WABinary_1.isJidBroadcast)(from)
87
99
  };
100
+ if (msgType === 'newsletter') {
101
+ fullMessage.newsletterServerId = +((_d = stanza.attrs) === null || _d === void 0 ? void 0 : _d.server_id);
102
+ }
88
103
  if (key.fromMe) {
89
104
  fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK;
90
105
  }
@@ -104,14 +119,34 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
104
119
  async decrypt() {
105
120
  var _a;
106
121
  let decryptables = 0;
107
- if (Array.isArray(stanza.content)) {
122
+ async function processSenderKeyDistribution(msg) {
123
+ if (msg.senderKeyDistributionMessage) {
124
+ try {
125
+ await repository.processSenderKeyDistributionMessage({
126
+ authorJid: author,
127
+ item: msg.senderKeyDistributionMessage
128
+ });
129
+ }
130
+ catch (err) {
131
+ logger.error({ key: fullMessage.key, err }, 'failed to process senderKeyDistribution');
132
+ }
133
+ }
134
+ }
135
+ if ((0, WABinary_1.isJidNewsletter)(fullMessage.key.remoteJid)) {
136
+ const node = (0, WABinary_1.getBinaryNodeChild)(stanza, 'plaintext');
137
+ const msg = WAProto_1.proto.Message.decode(node === null || node === void 0 ? void 0 : node.content);
138
+ await processSenderKeyDistribution(msg);
139
+ fullMessage.message = msg;
140
+ decryptables += 1;
141
+ }
142
+ else if (Array.isArray(stanza.content)) {
108
143
  for (const { tag, attrs, content } of stanza.content) {
109
144
  if (tag === 'verified_name' && content instanceof Uint8Array) {
110
145
  const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content);
111
146
  const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details);
112
147
  fullMessage.verifiedBizName = details.verifiedName;
113
148
  }
114
- if (tag !== 'enc') {
149
+ if (tag !== 'enc' && tag !== 'plaintext') {
115
150
  continue;
116
151
  }
117
152
  if (!(content instanceof Uint8Array)) {
@@ -138,22 +173,15 @@ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
138
173
  ciphertext: content
139
174
  });
140
175
  break;
176
+ case undefined:
177
+ msgBuffer = content;
178
+ break;
141
179
  default:
142
180
  throw new Error(`Unknown e2e type: ${e2eType}`);
143
181
  }
144
- let msg = WAProto_1.proto.Message.decode((0, generics_1.unpadRandomMax16)(msgBuffer));
145
- msg = ((_a = msg.deviceSentMessage) === null || _a === void 0 ? void 0 : _a.message) || msg;
146
- if (msg.senderKeyDistributionMessage) {
147
- try {
148
- await repository.processSenderKeyDistributionMessage({
149
- authorJid: author,
150
- item: msg.senderKeyDistributionMessage
151
- });
152
- }
153
- catch (err) {
154
- logger.error({ key: fullMessage.key, err }, 'failed to decrypt message');
155
- }
156
- }
182
+ let msg = WAProto_1.proto.Message.decode(tag === 'plaintext' ? msgBuffer : (0, generics_1.unpadRandomMax16)(msgBuffer));
183
+ msg = ((_a = msg === null || msg === void 0 ? void 0 : msg.deviceSentMessage) === null || _a === void 0 ? void 0 : _a.message) || msg;
184
+ await processSenderKeyDistribution(msg);
157
185
  if (fullMessage.message) {
158
186
  Object.assign(fullMessage.message, msg);
159
187
  }
@@ -4,7 +4,17 @@ import { Logger } from 'pino';
4
4
  import { proto } from '../../WAProto';
5
5
  import { BaileysEventEmitter, BaileysEventMap, BrowsersMap, WACallUpdateType, WAVersion } from '../Types';
6
6
  import { BinaryNode } from '../WABinary';
7
+ /**
8
+ const COMPANION_PLATFORM_MAP = {
9
+ 'Chrome': '49',
10
+ 'Edge': '50',
11
+ 'Firefox': '51',
12
+ 'Opera': '53',
13
+ 'Safari': '54'
14
+ }
15
+ */
7
16
  export declare const Browsers: BrowsersMap;
17
+ /** Other Browser Support for Paircode */
8
18
  export declare const getPlatformId: (browser: string) => any;
9
19
  export declare const BufferJSON: {
10
20
  replacer: (k: any, value: any) => any;
@@ -14,6 +24,7 @@ export declare const getKeyAuthor: (key: proto.IMessageKey | undefined | null, m
14
24
  export declare const writeRandomPadMax16: (msg: Uint8Array) => Buffer;
15
25
  export declare const unpadRandomMax16: (e: Uint8Array | Buffer) => Uint8Array;
16
26
  export declare const encodeWAMessage: (message: proto.IMessage) => Buffer;
27
+ export declare const encodeNewsletterMessage: (message: proto.IMessage) => Uint8Array;
17
28
  export declare const generateRegistrationId: () => number;
18
29
  export declare const encodeBigEndian: (e: number, t?: number) => Uint8Array;
19
30
  export declare const toNumber: (t: Long | number | null | undefined) => number;
@@ -33,6 +44,7 @@ export declare const delayCancellable: (ms: number) => {
33
44
  };
34
45
  export declare function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v: T) => void, reject: (error: any) => void) => void): Promise<T>;
35
46
  export declare const generateMessageIDV2: (userId?: string) => string;
47
+ export declare const generateMessageIDV3: (userId?: string) => string;
36
48
  export declare const generateMessageID: () => string;
37
49
  export declare function bindWaitForEvent<T extends keyof BaileysEventMap>(ev: BaileysEventEmitter, event: T): (check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => Promise<void>;
38
50
  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.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;
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.generateMessageIDV3 = exports.generateMessageIDV2 = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeNewsletterMessage = 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");
@@ -12,6 +12,7 @@ const WAProto_1 = require("../../WAProto");
12
12
  const baileys_version_json_1 = require("../Defaults/baileys-version.json");
13
13
  const Types_1 = require("../Types");
14
14
  const WABinary_1 = require("../WABinary");
15
+ /** Added Extra Browsers or Platforms*/
15
16
  const PLATFORM_MAP = {
16
17
  'aix': 'AIX',
17
18
  'darwin': 'Mac OS',
@@ -21,6 +22,15 @@ const PLATFORM_MAP = {
21
22
  'openbsd': 'OpenBSD',
22
23
  'sunos': 'Solaris'
23
24
  };
25
+ /**
26
+ const COMPANION_PLATFORM_MAP = {
27
+ 'Chrome': '49',
28
+ 'Edge': '50',
29
+ 'Firefox': '51',
30
+ 'Opera': '53',
31
+ 'Safari': '54'
32
+ }
33
+ */
24
34
  exports.Browsers = {
25
35
  ubuntu: (browser) => ['Ubuntu', browser, '22.04.4'],
26
36
  macOS: (browser) => ['Mac OS', browser, '14.4.1'],
@@ -29,9 +39,10 @@ exports.Browsers = {
29
39
  /** The appropriate browser based on your OS & release */
30
40
  appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
31
41
  };
42
+ /** Other Browser Support for Paircode */
32
43
  const getPlatformId = (browser) => {
33
44
  const platformType = WAProto_1.proto.DeviceProps.PlatformType[browser.toUpperCase()];
34
- return platformType ? platformType.toString().charCodeAt(0).toString() : '49'; //chrome
45
+ return platformType ? platformType.toString().charCodeAt(0).toString() : '51'; // Firefox
35
46
  };
36
47
  exports.getPlatformId = getPlatformId;
37
48
  exports.BufferJSON = {
@@ -74,6 +85,8 @@ const unpadRandomMax16 = (e) => {
74
85
  exports.unpadRandomMax16 = unpadRandomMax16;
75
86
  const encodeWAMessage = (message) => ((0, exports.writeRandomPadMax16)(WAProto_1.proto.Message.encode(message).finish()));
76
87
  exports.encodeWAMessage = encodeWAMessage;
88
+ const encodeNewsletterMessage = (message) => (WAProto_1.proto.Message.encode(message).finish());
89
+ exports.encodeNewsletterMessage = encodeNewsletterMessage;
77
90
  const generateRegistrationId = () => {
78
91
  return Uint16Array.from((0, crypto_1.randomBytes)(2))[0] & 16383;
79
92
  };
@@ -155,8 +168,7 @@ async function promiseTimeout(ms, promise) {
155
168
  return p;
156
169
  }
157
170
  exports.promiseTimeout = promiseTimeout;
158
- // inspired from whatsmeow code
159
- // https://github.com/tulir/whatsmeow/blob/64bc969fbe78d31ae0dd443b8d4c80a5d026d07a/send.go#L42
171
+ //Useless but still keep this to avoid unexpected errors and bugs
160
172
  const generateMessageIDV2 = (userId) => {
161
173
  const data = Buffer.alloc(8 + 20 + 16);
162
174
  data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
@@ -170,11 +182,19 @@ const generateMessageIDV2 = (userId) => {
170
182
  const random = (0, crypto_1.randomBytes)(16);
171
183
  random.copy(data, 28);
172
184
  const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
173
- return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 18);
185
+ return 'ANYAWEB' + hash.toString('hex').toUpperCase().substring(0, 18);
174
186
  };
175
187
  exports.generateMessageIDV2 = generateMessageIDV2;
188
+ //Message ID function for ShizoWeb
189
+ //This V3 is RollBack Update to old Message ID
190
+ const generateMessageIDV3 = (userId) => {
191
+ let swebfix = 'ANYAWEB';
192
+ let swebRandom = (0, crypto_1.randomBytes)(5).toString('hex').toUpperCase().substring(0, 10);
193
+ return swebfix + swebRandom;
194
+ };
195
+ exports.generateMessageIDV3 = generateMessageIDV3;
176
196
  // generate a random ID to attach to a message
177
- const generateMessageID = () => '3EB0' + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
197
+ const generateMessageID = () => 'ANYAWEB' + (0, crypto_1.randomBytes)(10).toString('hex').toUpperCase();
178
198
  exports.generateMessageID = generateMessageID;
179
199
  function bindWaitForEvent(ev, event) {
180
200
  return async (check, timeoutMs) => {
@@ -63,6 +63,15 @@ type EncryptedStreamOptions = {
63
63
  logger?: Logger;
64
64
  opts?: AxiosRequestConfig;
65
65
  };
66
+ export declare const prepareStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
67
+ mediaKey: undefined;
68
+ encWriteStream: Buffer;
69
+ fileLength: number;
70
+ fileSha256: Buffer;
71
+ fileEncSha256: undefined;
72
+ bodyPath: string | undefined;
73
+ didSaveToTmpPath: boolean;
74
+ }>;
66
75
  export declare const encryptedStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
67
76
  mediaKey: Buffer;
68
77
  encWriteStream: Readable;
@@ -92,7 +101,7 @@ export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logg
92
101
  */
93
102
  export declare const encryptMediaRetryRequest: (key: proto.IMessageKey, mediaKey: Buffer | Uint8Array, meId: string) => BinaryNode;
94
103
  export declare const decodeMediaRetryNode: (node: BinaryNode) => {
95
- key: proto.IMessageKey;
104
+ key: import("../Types").WAMessageKey;
96
105
  media?: {
97
106
  ciphertext: Uint8Array;
98
107
  iv: Uint8Array;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
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;
29
+ exports.getStatusCodeForMediaRetry = exports.decryptMediaRetryData = exports.decodeMediaRetryNode = exports.encryptMediaRetryRequest = exports.getWAUploadToServer = exports.extensionForMediaMessage = exports.downloadEncryptedContent = exports.downloadContentFromMessage = exports.getUrlFromDirectPath = exports.encryptedStream = exports.prepareStream = 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;
30
30
  const boom_1 = require("@hapi/boom");
31
31
  const axios_1 = __importDefault(require("axios"));
32
32
  const child_process_1 = require("child_process");
@@ -321,6 +321,50 @@ const getHttpStream = async (url, options = {}) => {
321
321
  return fetched.data;
322
322
  };
323
323
  exports.getHttpStream = getHttpStream;
324
+ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
325
+ const { stream, type } = await (0, exports.getStream)(media, opts);
326
+ logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
327
+ let bodyPath;
328
+ let didSaveToTmpPath = false;
329
+ try {
330
+ const buffer = await (0, exports.toBuffer)(stream);
331
+ if (type === 'file') {
332
+ bodyPath = media.url;
333
+ }
334
+ else if (saveOriginalFileIfRequired) {
335
+ bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
336
+ (0, fs_1.writeFileSync)(bodyPath, buffer);
337
+ didSaveToTmpPath = true;
338
+ }
339
+ const fileLength = buffer.length;
340
+ const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
341
+ stream === null || stream === void 0 ? void 0 : stream.destroy();
342
+ logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
343
+ return {
344
+ mediaKey: undefined,
345
+ encWriteStream: buffer,
346
+ fileLength,
347
+ fileSha256,
348
+ fileEncSha256: undefined,
349
+ bodyPath,
350
+ didSaveToTmpPath
351
+ };
352
+ }
353
+ catch (error) {
354
+ // destroy all streams with error
355
+ stream.destroy();
356
+ if (didSaveToTmpPath) {
357
+ try {
358
+ await fs_1.promises.unlink(bodyPath);
359
+ }
360
+ catch (err) {
361
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
362
+ }
363
+ }
364
+ throw error;
365
+ }
366
+ };
367
+ exports.prepareStream = prepareStream;
324
368
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
325
369
  const { stream, type } = await (0, exports.getStream)(media, opts);
326
370
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
@@ -526,17 +570,21 @@ function extensionForMediaMessage(message) {
526
570
  }
527
571
  exports.extensionForMediaMessage = extensionForMediaMessage;
528
572
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
529
- return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
573
+ return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
530
574
  var _a, _b;
531
575
  // send a query JSON to obtain the url & auth token to upload our media
532
576
  let uploadInfo = await refreshMediaConn(false);
533
577
  let urls;
534
578
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
535
579
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
580
+ let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
581
+ if (newsletter) {
582
+ media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
583
+ }
536
584
  for (const { hostname } of hosts) {
537
585
  logger.debug(`uploading to "${hostname}"`);
538
586
  const auth = encodeURIComponent(uploadInfo.auth); // the auth token
539
- const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
587
+ const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
540
588
  let result;
541
589
  try {
542
590
  const body = await axios_1.default.post(url, stream, {
@@ -556,7 +604,8 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
556
604
  if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
557
605
  urls = {
558
606
  mediaUrl: result.url,
559
- directPath: result.direct_path
607
+ directPath: result.direct_path,
608
+ handle: result.handle
560
609
  };
561
610
  break;
562
611
  }
@@ -111,14 +111,14 @@ const prepareWAMessageMedia = async (message, options) => {
111
111
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
112
112
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
113
113
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
114
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } = await (0, messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
114
+ const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
115
115
  logger,
116
116
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
117
117
  opts: options.options
118
118
  });
119
119
  // url safe Base64 encode the SHA256 hash of the body
120
- const fileEncSha256B64 = fileEncSha256.toString('base64');
121
- const [{ mediaUrl, directPath }] = await Promise.all([
120
+ const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
121
+ const [{ mediaUrl, directPath, handle }] = await Promise.all([
122
122
  (async () => {
123
123
  const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
124
124
  logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
@@ -159,7 +159,9 @@ const prepareWAMessageMedia = async (message, options) => {
159
159
  })(),
160
160
  ])
161
161
  .finally(async () => {
162
- encWriteStream.destroy();
162
+ if (!Buffer.isBuffer(encWriteStream)) {
163
+ encWriteStream.destroy();
164
+ }
163
165
  // remove tmp files
164
166
  if (didSaveToTmpPath && bodyPath) {
165
167
  await fs_1.promises.unlink(bodyPath);
@@ -168,13 +170,13 @@ const prepareWAMessageMedia = async (message, options) => {
168
170
  });
169
171
  const obj = Types_1.WAProto.Message.fromObject({
170
172
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
171
- url: mediaUrl,
173
+ url: handle ? undefined : mediaUrl,
172
174
  directPath,
173
- mediaKey,
174
- fileEncSha256,
175
+ mediaKey: mediaKey,
176
+ fileEncSha256: fileEncSha256,
175
177
  fileSha256,
176
178
  fileLength,
177
- mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
179
+ mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
178
180
  ...uploadData,
179
181
  media: undefined
180
182
  })
@@ -308,6 +310,41 @@ const generateWAMessageContent = async (message, options) => {
308
310
  message.disappearingMessagesInChat;
309
311
  m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
310
312
  }
313
+ else if ('groupInvite' in message) {
314
+ m.groupInviteMessage = {};
315
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
316
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
317
+ m.groupInviteMessage.caption = message.groupInvite.text;
318
+ m.groupInviteMessage.groupJid = message.groupInvite.jid;
319
+ m.groupInviteMessage.groupName = message.groupInvite.subject;
320
+ //TODO: use built-in interface and get disappearing mode info etc.
321
+ //TODO: cache / use store!?
322
+ if (options.getProfilePicUrl) {
323
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
324
+ if (pfpUrl) {
325
+ const resp = await axios_1.default.get(pfpUrl, { responseType: 'arraybuffer' });
326
+ if (resp.status === 200) {
327
+ m.groupInviteMessage.jpegThumbnail = resp.data;
328
+ }
329
+ }
330
+ }
331
+ }
332
+ else if ('pin' in message) {
333
+ m.pinInChatMessage = {};
334
+ m.messageContextInfo = {};
335
+ m.pinInChatMessage.key = message.pin;
336
+ m.pinInChatMessage.type = 1;
337
+ m.pinInChatMessage.senderTimestampMs = Date.now();
338
+ m.messageContextInfo.messageAddOnDurationInSecs = message.time || 86400;
339
+ }
340
+ else if ('unpin' in message) {
341
+ m.pinInChatMessage = {};
342
+ m.messageContextInfo = {};
343
+ m.pinInChatMessage.key = message.unpin;
344
+ m.pinInChatMessage.type = 2;
345
+ m.pinInChatMessage.senderTimestampMs = Date.now();
346
+ m.messageContextInfo.messageAddOnDurationInSecs = 0;
347
+ }
311
348
  else if ('buttonReply' in message) {
312
349
  switch (message.type) {
313
350
  case 'template':
@@ -464,7 +501,8 @@ const generateWAMessageFromContent = (jid, message, options) => {
464
501
  const key = (0, exports.getContentType)(innerMessage);
465
502
  const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
466
503
  const { quoted, userJid } = options;
467
- if (quoted) {
504
+ // only set quoted if isn't a newsletter message
505
+ if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
468
506
  const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
469
507
  let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
470
508
  const msgType = (0, exports.getContentType)(quotedMsg);
@@ -491,7 +529,9 @@ const generateWAMessageFromContent = (jid, message, options) => {
491
529
  // and it's not a protocol message -- delete, toggle disappear message
492
530
  key !== 'protocolMessage' &&
493
531
  // already not converted to disappearing message
494
- key !== 'ephemeralMessage') {
532
+ key !== 'ephemeralMessage' &&
533
+ // newsletter not accept disappearing messages
534
+ !(0, WABinary_1.isJidNewsletter)(jid)) {
495
535
  innerMessage[key].contextInfo = {
496
536
  ...(innerMessage[key].contextInfo || {}),
497
537
  expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
@@ -518,7 +558,7 @@ const generateWAMessage = async (jid, content, options) => {
518
558
  var _a;
519
559
  // ensure msg ID is with every log
520
560
  options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
521
- return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, options), options);
561
+ return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsletter)(jid), ...options }), options);
522
562
  };
523
563
  exports.generateWAMessage = generateWAMessage;
524
564
  /** Get the key to access the true type of content */
@@ -103,7 +103,7 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
103
103
  }
104
104
  exports.decryptPollVote = decryptPollVote;
105
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;
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
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)) };
@@ -268,22 +268,27 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
268
268
  chat.name = name;
269
269
  emitGroupUpdate({ subject: name });
270
270
  break;
271
+ case Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION:
272
+ const description = (_g = message.messageStubParameters) === null || _g === void 0 ? void 0 : _g[0];
273
+ chat.description = description;
274
+ emitGroupUpdate({ desc: description });
275
+ break;
271
276
  case Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
272
- const code = (_g = message.messageStubParameters) === null || _g === void 0 ? void 0 : _g[0];
277
+ const code = (_h = message.messageStubParameters) === null || _h === void 0 ? void 0 : _h[0];
273
278
  emitGroupUpdate({ inviteCode: code });
274
279
  break;
275
280
  case Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE:
276
- const memberAddValue = (_h = message.messageStubParameters) === null || _h === void 0 ? void 0 : _h[0];
281
+ const memberAddValue = (_j = message.messageStubParameters) === null || _j === void 0 ? void 0 : _j[0];
277
282
  emitGroupUpdate({ memberAddMode: memberAddValue === 'all_member_add' });
278
283
  break;
279
284
  case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE:
280
- const approvalMode = (_j = message.messageStubParameters) === null || _j === void 0 ? void 0 : _j[0];
285
+ const approvalMode = (_k = message.messageStubParameters) === null || _k === void 0 ? void 0 : _k[0];
281
286
  emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' });
282
287
  break;
283
288
  case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
284
- const participant = (_k = message.messageStubParameters) === null || _k === void 0 ? void 0 : _k[0];
285
- const action = (_l = message.messageStubParameters) === null || _l === void 0 ? void 0 : _l[1];
286
- const method = (_m = message.messageStubParameters) === null || _m === void 0 ? void 0 : _m[2];
289
+ const participant = (_l = message.messageStubParameters) === null || _l === void 0 ? void 0 : _l[0];
290
+ const action = (_m = message.messageStubParameters) === null || _m === void 0 ? void 0 : _m[1];
291
+ const method = (_o = message.messageStubParameters) === null || _o === void 0 ? void 0 : _o[2];
287
292
  emitGroupRequestJoin(participant, action, method);
288
293
  break;
289
294
  }
@@ -296,7 +301,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
296
301
  const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId);
297
302
  const pollCreatorJid = (0, generics_1.getKeyAuthor)(creationMsgKey, meIdNormalised);
298
303
  const voterJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised);
299
- const pollEncKey = (_o = pollMsg.messageContextInfo) === null || _o === void 0 ? void 0 : _o.messageSecret;
304
+ const pollEncKey = (_p = pollMsg.messageContextInfo) === null || _p === void 0 ? void 0 : _p.messageSecret;
300
305
  try {
301
306
  const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
302
307
  pollEncKey,
@@ -67,11 +67,6 @@ const parseAndInjectE2ESessions = async (node, repository) => {
67
67
  for (const node of nodes) {
68
68
  (0, WABinary_1.assertNodeErrorFree)(node);
69
69
  }
70
- // Most of the work in repository.injectE2ESession is CPU intensive, not IO
71
- // So Promise.all doesn't really help here,
72
- // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
73
- // This way we chunk it in smaller parts and between those parts we can yield to the event loop
74
- // It's rare case when you need to E2E sessions for so many users, but it's possible
75
70
  const chunkSize = 100;
76
71
  const chunks = (0, lodash_1.chunk)(nodes, chunkSize);
77
72
  for (const nodesChunk of chunks) {
@@ -1,3 +1,2 @@
1
- /// <reference types="node" />
2
1
  import type { BinaryNode, BinaryNodeCodingOptions } from './types';
3
- export declare const encodeBinaryNode: (node: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => Buffer;
2
+ export declare const encodeBinaryNode: ({ tag, attrs, content }: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => number[];
@@ -26,12 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.encodeBinaryNode = void 0;
27
27
  const constants = __importStar(require("./constants"));
28
28
  const jid_utils_1 = require("./jid-utils");
29
- const encodeBinaryNode = (node, opts = constants, buffer = [0]) => {
30
- const encoded = encodeBinaryNodeInner(node, opts, buffer);
31
- return Buffer.from(encoded);
32
- };
33
- exports.encodeBinaryNode = encodeBinaryNode;
34
- const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
29
+ const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0]) => {
35
30
  const { TAGS, TOKEN_MAP } = opts;
36
31
  const pushByte = (value) => buffer.push(value & 0xff);
37
32
  const pushInt = (value, n, littleEndian = false) => {
@@ -219,7 +214,7 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
219
214
  else if (Array.isArray(content)) {
220
215
  writeListStart(content.length);
221
216
  for (const item of content) {
222
- encodeBinaryNodeInner(item, opts, buffer);
217
+ (0, exports.encodeBinaryNode)(item, opts, buffer);
223
218
  }
224
219
  }
225
220
  else if (typeof content === 'undefined') {
@@ -230,3 +225,4 @@ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
230
225
  }
231
226
  return buffer;
232
227
  };
228
+ exports.encodeBinaryNode = encodeBinaryNode;
@@ -3,7 +3,7 @@ export declare const OFFICIAL_BIZ_JID = "16505361212@c.us";
3
3
  export declare const SERVER_JID = "server@c.us";
4
4
  export declare const PSA_WID = "0@c.us";
5
5
  export declare const STORIES_JID = "status@broadcast";
6
- export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call' | 'lid';
6
+ export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call' | 'lid' | 'newsletter';
7
7
  export type JidWithDevice = {
8
8
  user: string;
9
9
  device?: number;
@@ -24,6 +24,8 @@ export declare const isLidUser: (jid: string | undefined) => boolean | undefined
24
24
  export declare const isJidBroadcast: (jid: string | undefined) => boolean | undefined;
25
25
  /** is the jid a group */
26
26
  export declare const isJidGroup: (jid: string | undefined) => boolean | undefined;
27
+ /** is the jid a newsletter */
28
+ export declare const isJidNewsletter: (jid: string | undefined) => boolean | undefined;
27
29
  /** is the jid the status broadcast */
28
30
  export declare const isJidStatusBroadcast: (jid: string) => boolean;
29
31
  export declare const jidNormalizedUser: (jid: string | undefined) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jidNormalizedUser = exports.isJidStatusBroadcast = exports.isJidGroup = exports.isJidBroadcast = exports.isLidUser = exports.isJidUser = exports.areJidsSameUser = exports.jidDecode = exports.jidEncode = exports.STORIES_JID = exports.PSA_WID = exports.SERVER_JID = exports.OFFICIAL_BIZ_JID = exports.S_WHATSAPP_NET = void 0;
3
+ exports.jidNormalizedUser = exports.isJidStatusBroadcast = exports.isJidNewsletter = exports.isJidGroup = exports.isJidBroadcast = exports.isLidUser = exports.isJidUser = exports.areJidsSameUser = exports.jidDecode = exports.jidEncode = exports.STORIES_JID = exports.PSA_WID = exports.SERVER_JID = exports.OFFICIAL_BIZ_JID = exports.S_WHATSAPP_NET = void 0;
4
4
  exports.S_WHATSAPP_NET = '@s.whatsapp.net';
5
5
  exports.OFFICIAL_BIZ_JID = '16505361212@c.us';
6
6
  exports.SERVER_JID = 'server@c.us';
@@ -45,6 +45,9 @@ exports.isJidBroadcast = isJidBroadcast;
45
45
  /** is the jid a group */
46
46
  const isJidGroup = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@g.us'));
47
47
  exports.isJidGroup = isJidGroup;
48
+ /** is the jid a newsletter */
49
+ const isJidNewsletter = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@newsletter'));
50
+ exports.isJidNewsletter = isJidNewsletter;
48
51
  /** is the jid the status broadcast */
49
52
  const isJidStatusBroadcast = (jid) => jid === 'status@broadcast';
50
53
  exports.isJidStatusBroadcast = isJidStatusBroadcast;