@itsliaaa/baileys 0.1.29 โ†’ 0.1.30

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.
package/README.md CHANGED
@@ -382,6 +382,28 @@ sock.sendMessage(jid, {
382
382
  })
383
383
  ```
384
384
 
385
+ #### ๐Ÿ‘ฅ Group Invite
386
+
387
+ ```javascript
388
+ const groupJid = '1201111111111@g.us'
389
+ const groupName = '@itsliaaa/baileys'
390
+ const inviteCode = groupUrl
391
+ .split('chat.whatsapp.com/')[1]?
392
+ .split('?')[0]
393
+
394
+ sock.sendMessage(jid, {
395
+ groupInvite: {
396
+ inviteCode,
397
+ inviteExpiration: Date.now() + 86400000,
398
+ text: '๐Ÿ‘‹๐Ÿป Hello, we invite you to join our group.',
399
+ jid: groupJid,
400
+ subject: groupName,
401
+ }
402
+ }, {
403
+ quoted: message
404
+ })
405
+ ```
406
+
385
407
  #### ๐Ÿ“Š Poll
386
408
 
387
409
  ```javascript
@@ -82,31 +82,24 @@ const assertColor = async (color) => {
82
82
  return assertedColor;
83
83
  }
84
84
  };
85
+ // Lia@Changes 21-04-26 --- Refactor prepareWAMessageMedia function
85
86
  export const prepareWAMessageMedia = async (message, options) => {
86
87
  const logger = options.logger;
87
- let mediaType;
88
- for (const key of MEDIA_KEYS) {
89
- if (key in message) {
90
- mediaType = key;
91
- }
92
- }
88
+ const mediaType = MEDIA_KEYS.find(key => key in message);
93
89
  if (!mediaType) {
94
90
  throw new Boom('Invalid media type', { statusCode: 400 });
95
91
  }
96
- const uploadData = {
97
- ...message,
98
- media: message[mediaType]
99
- };
92
+ const uploadData = { ...message };
93
+ const mediaPayload = uploadData[mediaType];
94
+ delete uploadData[mediaType];
100
95
  if (uploadData.image || uploadData.video) {
101
96
  uploadData.annotations = mediaAnnotation;
102
97
  }
103
- delete uploadData[mediaType];
104
- // check if cacheable + generate cache key
105
- const cacheableKey = typeof uploadData.media === 'object' &&
106
- 'url' in uploadData.media &&
107
- !!uploadData.media.url &&
98
+ const cacheableKey = typeof mediaPayload === 'object' &&
99
+ 'url' in mediaPayload &&
100
+ !!mediaPayload.url &&
108
101
  !!options.mediaCache &&
109
- mediaType + ':' + uploadData.media.url;
102
+ `${mediaType}:${mediaPayload.url}`;
110
103
  if (mediaType === 'document' && !uploadData.fileName) {
111
104
  uploadData.fileName = LIBRARY_NAME;
112
105
  }
@@ -119,7 +112,7 @@ export const prepareWAMessageMedia = async (message, options) => {
119
112
  logger?.debug({ cacheableKey }, 'got media cache hit');
120
113
  const obj = proto.Message.decode(mediaBuff);
121
114
  const key = `${mediaType}Message`;
122
- Object.assign(obj[key], { ...uploadData, media: undefined });
115
+ Object.assign(obj[key], uploadData);
123
116
  return obj;
124
117
  }
125
118
  }
@@ -129,142 +122,118 @@ export const prepareWAMessageMedia = async (message, options) => {
129
122
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
130
123
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
131
124
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
125
+ let mediaUrl,
126
+ directPath,
127
+ thumbnailDirectPath,
128
+ thumbnailSha256,
129
+ fileSha256,
130
+ fileLength,
131
+ mediaKey,
132
+ fileEncSha256;
132
133
  // Lia@Changes 06-02-26 --- Add few support for sending media to newsletter (โ โ‰งโ โ–ฝโ โ‰ฆโ )
133
134
  if (isNewsletter) {
134
135
  logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
135
- const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger);
136
+ const rawData = await getRawMediaUploadData(mediaPayload, options.mediaTypeOverride || mediaType, logger);
137
+ fileSha256 = rawData.fileSha256;
138
+ fileLength = rawData.fileLength;
139
+ const filePath = rawData.filePath;
136
140
  const fileSha256B64 = fileSha256.toString('base64');
137
- const [{ mediaUrl, directPath, thumbnailDirectPath, thumbnailSha256 }] = await Promise.all([
138
- (async () => {
139
- const result = options.upload(filePath, {
140
- fileEncSha256B64: fileSha256B64,
141
- mediaType,
142
- timeoutMs: options.mediaUploadTimeoutMs,
143
- newsletter: isNewsletter
144
- });
145
- logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
146
- return result;
147
- })(),
141
+ const [uploadResult] = await Promise.all([
142
+ options.upload(filePath, {
143
+ fileEncSha256B64: fileSha256B64,
144
+ mediaType,
145
+ timeoutMs: options.mediaUploadTimeoutMs,
146
+ newsletter: true
147
+ }),
148
148
  (async () => {
149
149
  try {
150
150
  if (requiresThumbnailComputation) {
151
151
  const { thumbnail } = await generateThumbnail(filePath, mediaType, options);
152
152
  uploadData.jpegThumbnail = thumbnail;
153
- logger?.debug('generated thumbnail');
154
153
  }
155
154
  if (requiresDurationComputation) {
156
155
  uploadData.seconds = await getAudioDuration(filePath);
157
- logger?.debug('computed audio duration');
158
156
  }
159
157
  }
160
158
  catch (error) {
161
159
  logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
162
160
  }
163
161
  })()
164
- ]).finally(async () => {
165
- try {
166
- await fs.unlink(filePath);
167
- logger?.debug('removed tmp files');
168
- }
169
- catch (error) {
170
- logger?.warn('failed to remove tmp file');
171
- }
172
- });
173
- delete uploadData.media;
174
- const obj = proto.Message.create({
175
- // todo: add more support here
176
- [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
177
- url: mediaUrl,
178
- directPath,
179
- fileSha256,
180
- fileLength,
181
- thumbnailDirectPath,
182
- thumbnailSha256,
183
- ...uploadData
184
- })
185
- });
186
- if (uploadData.ptv) {
187
- obj.ptvMessage = obj.videoMessage;
188
- delete obj.videoMessage;
189
- }
190
- if (obj.stickerMessage) {
191
- obj.stickerMessage.stickerSentTs = Date.now();
192
- }
193
- if (cacheableKey) {
194
- logger?.debug({ cacheableKey }, 'set cache');
195
- await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
196
- }
197
- return obj;
162
+ ]);
163
+ // todo: add more support here
164
+ mediaUrl = uploadResult.mediaUrl;
165
+ directPath = uploadResult.directPath;
166
+ thumbnailDirectPath = uploadResult.thumbnailDirectPath;
167
+ thumbnailSha256 = uploadResult.thumbnailSha256;
168
+ fs.unlink(filePath).catch(() => logger?.warn('failed to remove tmp file'));
198
169
  }
199
- const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
200
- logger,
201
- saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
202
- opts: options.options
203
- });
204
- const fileEncSha256B64 = fileEncSha256.toString('base64');
205
- const [{ mediaUrl, directPath }] = await Promise.all([
206
- (async () => {
207
- const result = await options.upload(encFilePath, {
170
+ else {
171
+ const encryptedData = await encryptedStream(mediaPayload, options.mediaTypeOverride || mediaType, {
172
+ logger,
173
+ saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
174
+ opts: options.options
175
+ });
176
+ mediaKey = encryptedData.mediaKey;
177
+ fileEncSha256 = encryptedData.fileEncSha256;
178
+ fileSha256 = encryptedData.fileSha256;
179
+ fileLength = encryptedData.fileLength;
180
+ const encFilePath = encryptedData.encFilePath;
181
+ const originalFilePath = encryptedData.originalFilePath;
182
+ const fileEncSha256B64 = fileEncSha256.toString('base64');
183
+ const [uploadResult] = await Promise.all([
184
+ options.upload(encFilePath, {
208
185
  fileEncSha256B64,
209
186
  mediaType,
210
187
  timeoutMs: options.mediaUploadTimeoutMs
211
- });
212
- logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
213
- return result;
214
- })(),
215
- (async () => {
216
- try {
217
- if (requiresThumbnailComputation) {
218
- const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
219
- uploadData.jpegThumbnail = thumbnail;
220
- if (!uploadData.width && originalImageDimensions) {
221
- uploadData.width = originalImageDimensions.width;
222
- uploadData.height = originalImageDimensions.height;
223
- logger?.debug('set dimensions');
188
+ }),
189
+ (async () => {
190
+ try {
191
+ if (requiresThumbnailComputation) {
192
+ const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options);
193
+ uploadData.jpegThumbnail = thumbnail;
194
+ if (!uploadData.width && originalImageDimensions) {
195
+ uploadData.width = originalImageDimensions.width;
196
+ uploadData.height = originalImageDimensions.height;
197
+ }
198
+ }
199
+ if (requiresDurationComputation) {
200
+ uploadData.seconds = await getAudioDuration(originalFilePath);
201
+ }
202
+ if (requiresWaveformProcessing) {
203
+ uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
204
+ }
205
+ if (requiresAudioBackground) {
206
+ uploadData.backgroundArgb = await assertColor(options.backgroundColor);
224
207
  }
225
- logger?.debug('generated thumbnail');
226
- }
227
- if (requiresDurationComputation) {
228
- uploadData.seconds = await getAudioDuration(originalFilePath);
229
- logger?.debug('computed audio duration');
230
- }
231
- if (requiresWaveformProcessing) {
232
- uploadData.waveform = await getAudioWaveform(originalFilePath, logger);
233
- logger?.debug('processed waveform');
234
208
  }
235
- if (requiresAudioBackground) {
236
- uploadData.backgroundArgb = await assertColor(options.backgroundColor);
237
- logger?.debug('computed backgroundColor audio status');
209
+ catch (error) {
210
+ logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
238
211
  }
239
- }
240
- catch (error) {
241
- logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
242
- }
243
- })()
244
- ]).finally(async () => {
245
- try {
246
- await fs.unlink(encFilePath);
247
- if (originalFilePath) {
248
- await fs.unlink(originalFilePath);
249
- }
250
- logger?.debug('removed tmp files');
251
- }
252
- catch (error) {
253
- logger?.warn('failed to remove tmp file');
254
- }
255
- });
256
- delete uploadData.media;
212
+ })()
213
+ ]);
214
+ mediaUrl = uploadResult.mediaUrl;
215
+ directPath = uploadResult.directPath;
216
+ fs.unlink(encFilePath).catch(() => logger?.warn('failed to remove tmp file'));
217
+ fs.unlink(originalFilePath).catch(() => logger?.warn('failed to remove tmp file'));
218
+ }
219
+ const messagePayload = {
220
+ url: mediaUrl,
221
+ directPath,
222
+ fileSha256,
223
+ fileLength,
224
+ ...uploadData
225
+ };
226
+ if (isNewsletter) {
227
+ messagePayload.thumbnailDirectPath = thumbnailDirectPath;
228
+ messagePayload.thumbnailSha256 = thumbnailSha256;
229
+ }
230
+ else {
231
+ messagePayload.mediaKey = mediaKey;
232
+ messagePayload.fileEncSha256 = fileEncSha256;
233
+ messagePayload.mediaKeyTimestamp = unixTimestampSeconds();
234
+ }
257
235
  const obj = proto.Message.create({
258
- [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
259
- url: mediaUrl,
260
- directPath,
261
- mediaKey,
262
- fileEncSha256,
263
- fileSha256,
264
- fileLength,
265
- mediaKeyTimestamp: unixTimestampSeconds(),
266
- ...uploadData
267
- })
236
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject(messagePayload)
268
237
  });
269
238
  if (uploadData.ptv) {
270
239
  obj.ptvMessage = obj.videoMessage;
@@ -274,8 +243,8 @@ export const prepareWAMessageMedia = async (message, options) => {
274
243
  obj.stickerMessage.stickerSentTs = Date.now();
275
244
  }
276
245
  if (cacheableKey) {
277
- logger?.debug({ cacheableKey }, 'set cache');
278
- await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
246
+ logger?.debug({ cacheableKey }, 'set cache (background)');
247
+ options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish()).catch(() => {});
279
248
  }
280
249
  return obj;
281
250
  };
@@ -524,8 +493,8 @@ const prepareStickerPackMessage = async (message, options) => {
524
493
  }
525
494
  const content = obj;
526
495
  if (cacheableKey) {
527
- options.logger?.debug({ cacheableKey }, 'set cache');
528
- await options.mediaCache.set(cacheableKey, WAProto.Message.StickerPackMessage.encode(content).finish());
496
+ options.logger?.debug({ cacheableKey }, 'set cache (background)');
497
+ options.mediaCache.set(cacheableKey, WAProto.Message.StickerPackMessage.encode(content).finish());
529
498
  }
530
499
  return WAProto.Message.StickerPackMessage.fromObject(content);
531
500
  };
@@ -1319,6 +1288,12 @@ export const generateWAMessageContent = async (message, options) => {
1319
1288
  }
1320
1289
  m = { invoiceMessage };
1321
1290
  }
1291
+ if (shouldIncludeReportingToken(m)) {
1292
+ m.messageContextInfo = m.messageContextInfo || {};
1293
+ if (!m.messageContextInfo.messageSecret) {
1294
+ m.messageContextInfo.messageSecret = randomBytes(32);
1295
+ }
1296
+ }
1322
1297
  // Lia@Changes 31-01-26 --- Add direct externalAdReply access (no need to create contextInfo first)
1323
1298
  if (hasOptionalProperty(message, 'externalAdReply') && !!message.externalAdReply) {
1324
1299
  const messageType = Object.keys(m)[0];
@@ -1336,9 +1311,9 @@ export const generateWAMessageContent = async (message, options) => {
1336
1311
  mediaType: content.mediaType || 1,
1337
1312
  mediaUrl: content.url,
1338
1313
  renderLargerThumbnail: content.largeThumbnail,
1339
- sourceUrl: content.url + '?update=' + Date.now(),
1314
+ sourceUrl: content.url,
1340
1315
  thumbnail: content.thumbnail,
1341
- thumbnailUrl: content.url,
1316
+ thumbnailUrl: content.url + '?update=' + Date.now(),
1342
1317
  title: content.title || LIBRARY_NAME
1343
1318
  };
1344
1319
  delete externalAdReply.subTitle;
@@ -1434,12 +1409,6 @@ export const generateWAMessageContent = async (message, options) => {
1434
1409
  }
1435
1410
  }
1436
1411
  }
1437
- if (shouldIncludeReportingToken(m)) {
1438
- m.messageContextInfo = m.messageContextInfo || {};
1439
- if (!m.messageContextInfo.messageSecret) {
1440
- m.messageContextInfo.messageSecret = randomBytes(32);
1441
- }
1442
- }
1443
1412
  return proto.Message.create(m);
1444
1413
  };
1445
1414
  export const generateWAMessageFromContent = (jid, message, options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itsliaaa/baileys",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Enhanced Baileys v7 with fixed newsletter media upload, plus support for interactive messages, albums, and more message types.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",