@queenanya/baileys 7.1.1 → 7.1.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.
@@ -14,7 +14,9 @@ export type WAMessage = proto.IWebMessageInfo;
14
14
  export type WAMessageContent = proto.IMessage;
15
15
  export type WAContactMessage = proto.Message.IContactMessage;
16
16
  export type WAContactsArrayMessage = proto.Message.IContactsArrayMessage;
17
- export type WAMessageKey = proto.IMessageKey;
17
+ export type WAMessageKey = proto.IMessageKey & {
18
+ server_id?: string;
19
+ };
18
20
  export type WATextMessage = proto.Message.IExtendedTextMessage;
19
21
  export type WAContextInfo = proto.IContextInfo;
20
22
  export type WALocationMessage = proto.Message.ILocationMessage;
@@ -156,6 +158,11 @@ export type AnyRegularMessageContent = (({
156
158
  type: 'template' | 'plain';
157
159
  } | {
158
160
  listReply: Omit<proto.Message.IListResponseMessage, 'contextInfo'>;
161
+ } | {
162
+ pin: WAMessageKey;
163
+ time: 86400 | 604800 | 2592000;
164
+ } | {
165
+ unpin: WAMessageKey;
159
166
  } | {
160
167
  product: WASendableProduct;
161
168
  businessOwnerJid?: string;
@@ -214,13 +221,16 @@ export type MiscMessageGenerationOptions = MinimalRelayOptions & {
214
221
  export type MessageGenerationOptionsFromContent = MiscMessageGenerationOptions & {
215
222
  userJid: string;
216
223
  };
217
- export type WAMediaUploadFunction = (readStream: Readable, opts: {
224
+ export type WAMediaUploadFunctionOpts = {
218
225
  fileEncSha256B64: string;
219
226
  mediaType: MediaType;
227
+ newsletter?: boolean;
220
228
  timeoutMs?: number;
221
- }) => Promise<{
229
+ };
230
+ export type WAMediaUploadFunction = (readStream: Readable | Buffer, opts: WAMediaUploadFunctionOpts) => Promise<{
222
231
  mediaUrl: string;
223
232
  directPath: string;
233
+ handle?: string;
224
234
  }>;
225
235
  export type MediaGenerationOptions = {
226
236
  logger?: Logger;
@@ -231,6 +241,8 @@ export type MediaGenerationOptions = {
231
241
  mediaUploadTimeoutMs?: number;
232
242
  options?: AxiosRequestConfig;
233
243
  backgroundColor?: string;
244
+ /** The message is for newsletter? */
245
+ newsletter?: boolean;
234
246
  font?: number;
235
247
  };
236
248
  export type MessageContentGenerationOptions = MediaGenerationOptions & {
@@ -0,0 +1,79 @@
1
+ import { proto } from '../../WAProto';
2
+ export type NewsletterReactionMode = 'ALL' | 'BASIC' | 'NONE';
3
+ export type NewsletterState = 'ACTIVE' | 'GEOSUSPENDED' | 'SUSPENDED';
4
+ export type NewsletterVerification = 'VERIFIED' | 'UNVERIFIED';
5
+ export type NewsletterMute = 'ON' | 'OFF' | 'UNDEFINED';
6
+ export type NewsletterViewRole = 'ADMIN' | 'GUEST' | 'OWNER' | 'SUBSCRIBER';
7
+ export type NewsletterViewerMetadata = {
8
+ mute: NewsletterMute;
9
+ view_role: NewsletterViewRole;
10
+ };
11
+ export type NewsletterMetadata = {
12
+ /**jid of newsletter */
13
+ id: string;
14
+ /**state of newsletter */
15
+ state: NewsletterState;
16
+ /**creation timestamp of newsletter */
17
+ creation_time: number;
18
+ /**name of newsletter */
19
+ name: string;
20
+ /**timestamp of last name modification of newsletter */
21
+ nameTime: number;
22
+ /**description of newsletter */
23
+ description: string;
24
+ /**timestamp of last description modification of newsletter */
25
+ descriptionTime: number;
26
+ /**invite code of newsletter */
27
+ invite: string;
28
+ /**i dont know */
29
+ handle: null;
30
+ /**direct path of picture */
31
+ picture: string | null;
32
+ /**direct path of picture preview (lower quality) */
33
+ preview: string | null;
34
+ /**reaction mode of newsletter */
35
+ reaction_codes?: NewsletterReactionMode;
36
+ /**subscribers count of newsletter */
37
+ subscribers: number;
38
+ /**verification state of newsletter */
39
+ verification: NewsletterVerification;
40
+ /**viewer metadata */
41
+ viewer_metadata: NewsletterViewerMetadata;
42
+ };
43
+ export type SubscriberAction = 'promote' | 'demote';
44
+ export type ReactionModeUpdate = {
45
+ reaction_codes: {
46
+ blocked_codes: null;
47
+ enabled_ts_sec: null;
48
+ value: NewsletterReactionMode;
49
+ };
50
+ };
51
+ /**only exists reaction mode update */
52
+ export type NewsletterSettingsUpdate = ReactionModeUpdate;
53
+ export type NewsletterReaction = {
54
+ count: number;
55
+ code: string;
56
+ };
57
+ export type NewsletterFetchedUpdate = {
58
+ /**id of message in newsletter, starts from 100 */
59
+ server_id: string;
60
+ /**count of views in this message */
61
+ views?: number;
62
+ /**reactions in this message */
63
+ reactions: NewsletterReaction[];
64
+ /**the message, if you requested only updates, you will not receive message */
65
+ message?: proto.IWebMessageInfo;
66
+ };
67
+ export declare enum MexOperations {
68
+ PROMOTE = "NotificationNewsletterAdminPromote",
69
+ DEMOTE = "NotificationNewsletterAdminDemote",
70
+ UPDATE = "NotificationNewsletterUpdate"
71
+ }
72
+ export declare enum XWAPaths {
73
+ PROMOTE = "xwa2_notify_newsletter_admin_promote",
74
+ DEMOTE = "xwa2_notify_newsletter_admin_demote",
75
+ ADMIN_COUNT = "xwa2_newsletter_admin",
76
+ CREATE = "xwa2_newsletter_create",
77
+ NEWSLETTER = "xwa2_newsletter",
78
+ METADATA_UPDATE = "xwa2_notify_newsletter_on_metadata_update"
79
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XWAPaths = exports.MexOperations = void 0;
4
+ var MexOperations;
5
+ (function (MexOperations) {
6
+ MexOperations["PROMOTE"] = "NotificationNewsletterAdminPromote";
7
+ MexOperations["DEMOTE"] = "NotificationNewsletterAdminDemote";
8
+ MexOperations["UPDATE"] = "NotificationNewsletterUpdate";
9
+ })(MexOperations = exports.MexOperations || (exports.MexOperations = {}));
10
+ var XWAPaths;
11
+ (function (XWAPaths) {
12
+ XWAPaths["PROMOTE"] = "xwa2_notify_newsletter_admin_promote";
13
+ XWAPaths["DEMOTE"] = "xwa2_notify_newsletter_admin_demote";
14
+ XWAPaths["ADMIN_COUNT"] = "xwa2_newsletter_admin";
15
+ XWAPaths["CREATE"] = "xwa2_newsletter_create";
16
+ XWAPaths["NEWSLETTER"] = "xwa2_newsletter";
17
+ XWAPaths["METADATA_UPDATE"] = "xwa2_notify_newsletter_on_metadata_update";
18
+ })(XWAPaths = exports.XWAPaths || (exports.XWAPaths = {}));
@@ -4,6 +4,7 @@ export * from './Chat';
4
4
  export * from './Contact';
5
5
  export * from './State';
6
6
  export * from './Message';
7
+ export * from './Newsletter';
7
8
  export * from './Socket';
8
9
  export * from './Events';
9
10
  export * from './Product';
@@ -14,6 +15,7 @@ import { SocketConfig } from './Socket';
14
15
  export type UserFacingSocketConfig = Partial<SocketConfig> & {
15
16
  auth: AuthenticationState;
16
17
  };
18
+ /** Other Browser Support for Paircode */
17
19
  export type BrowsersMap = {
18
20
  ubuntu(browser: string): [string, string, string];
19
21
  macOS(browser: string): [string, string, string];
@@ -21,6 +21,7 @@ __exportStar(require("./Chat"), exports);
21
21
  __exportStar(require("./Contact"), exports);
22
22
  __exportStar(require("./State"), exports);
23
23
  __exportStar(require("./Message"), exports);
24
+ __exportStar(require("./Newsletter"), exports);
24
25
  __exportStar(require("./Socket"), exports);
25
26
  __exportStar(require("./Events"), exports);
26
27
  __exportStar(require("./Product"), exports);
@@ -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;
@@ -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.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,6 @@ 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
160
171
  const generateMessageIDV2 = (userId) => {
161
172
  const data = Buffer.alloc(8 + 20 + 16);
162
173
  data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
@@ -170,11 +181,11 @@ const generateMessageIDV2 = (userId) => {
170
181
  const random = (0, crypto_1.randomBytes)(16);
171
182
  random.copy(data, 28);
172
183
  const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
173
- return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 18);
184
+ return '3EB0' + hash.toString('hex').toUpperCase().substring(0, 16);
174
185
  };
175
186
  exports.generateMessageIDV2 = generateMessageIDV2;
176
187
  // generate a random ID to attach to a message
177
- const generateMessageID = () => '3EB0' + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
188
+ const generateMessageID = () => '3EB0' + (0, crypto_1.randomBytes)(12).toString('hex').toUpperCase();
178
189
  exports.generateMessageID = generateMessageID;
179
190
  function bindWaitForEvent(ev, event) {
180
191
  return async (check, timeoutMs) => {
@@ -1,4 +1,2 @@
1
- declare const _default: import("pino").Logger<{
2
- timestamp: () => string;
3
- }>;
1
+ declare const _default: import("pino").Logger<never>;
4
2
  export default _default;
@@ -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,22 @@ const generateWAMessageContent = async (message, options) => {
308
310
  message.disappearingMessagesInChat;
309
311
  m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
310
312
  }
313
+ else if ('pin' in message) {
314
+ m.pinInChatMessage = {};
315
+ m.messageContextInfo = {};
316
+ m.pinInChatMessage.key = message.pin;
317
+ m.pinInChatMessage.type = 1;
318
+ m.pinInChatMessage.senderTimestampMs = Date.now();
319
+ m.messageContextInfo.messageAddOnDurationInSecs = message.time || 86400;
320
+ }
321
+ else if ('unpin' in message) {
322
+ m.pinInChatMessage = {};
323
+ m.messageContextInfo = {};
324
+ m.pinInChatMessage.key = message.unpin;
325
+ m.pinInChatMessage.type = 2;
326
+ m.pinInChatMessage.senderTimestampMs = Date.now();
327
+ m.messageContextInfo.messageAddOnDurationInSecs = 0;
328
+ }
311
329
  else if ('buttonReply' in message) {
312
330
  switch (message.type) {
313
331
  case 'template':
@@ -464,7 +482,8 @@ const generateWAMessageFromContent = (jid, message, options) => {
464
482
  const key = (0, exports.getContentType)(innerMessage);
465
483
  const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
466
484
  const { quoted, userJid } = options;
467
- if (quoted) {
485
+ // only set quoted if isn't a newsletter message
486
+ if (quoted && !(0, WABinary_1.isJidNewsletter)(jid)) {
468
487
  const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
469
488
  let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
470
489
  const msgType = (0, exports.getContentType)(quotedMsg);
@@ -491,7 +510,9 @@ const generateWAMessageFromContent = (jid, message, options) => {
491
510
  // and it's not a protocol message -- delete, toggle disappear message
492
511
  key !== 'protocolMessage' &&
493
512
  // already not converted to disappearing message
494
- key !== 'ephemeralMessage') {
513
+ key !== 'ephemeralMessage' &&
514
+ // newsletter not accept disappearing messages
515
+ !(0, WABinary_1.isJidNewsletter)(jid)) {
495
516
  innerMessage[key].contextInfo = {
496
517
  ...(innerMessage[key].contextInfo || {}),
497
518
  expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
@@ -518,7 +539,7 @@ const generateWAMessage = async (jid, content, options) => {
518
539
  var _a;
519
540
  // ensure msg ID is with every log
520
541
  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);
542
+ return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: (0, WABinary_1.isJidNewsletter)(jid), ...options }), options);
522
543
  };
523
544
  exports.generateWAMessage = generateWAMessage;
524
545
  /** Get the key to access the true type of content */
@@ -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[];