@genuxofficial/baileys 1.0.0 → 3.0.0

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 (80) hide show
  1. package/README.md +5 -1
  2. package/WAProto/WAProto.proto +1385 -96
  3. package/WAProto/index.d.ts +19244 -2787
  4. package/WAProto/index.js +138202 -74217
  5. package/engine-requirements.js +10 -0
  6. package/lib/Defaults/baileys-version.json +1 -1
  7. package/lib/Defaults/index.js +1 -0
  8. package/lib/Socket/business.d.ts +47 -17
  9. package/lib/Socket/chats.d.ts +10 -9
  10. package/lib/Socket/chats.js +36 -16
  11. package/lib/Socket/groups.d.ts +12 -11
  12. package/lib/Socket/groups.js +16 -3
  13. package/lib/Socket/index.d.ts +52 -22
  14. package/lib/Socket/messages-recv.d.ts +46 -15
  15. package/lib/Socket/messages-recv.js +158 -23
  16. package/lib/Socket/messages-send.d.ts +39 -11
  17. package/lib/Socket/messages-send.js +188 -22
  18. package/lib/Socket/newsletter.d.ts +137 -0
  19. package/lib/Socket/newsletter.js +256 -0
  20. package/lib/Socket/socket.d.ts +4 -4
  21. package/lib/Socket/socket.js +25 -12
  22. package/lib/Socket/usync.d.ts +5 -5
  23. package/lib/Store/index.d.ts +1 -2
  24. package/lib/Store/index.js +1 -3
  25. package/lib/Store/make-in-memory-store.js +14 -5
  26. package/lib/Types/Chat.d.ts +6 -5
  27. package/lib/Types/Events.d.ts +27 -0
  28. package/lib/Types/GroupMetadata.d.ts +6 -0
  29. package/lib/Types/Label.d.ts +0 -11
  30. package/lib/Types/Message.d.ts +150 -12
  31. package/lib/Types/Message.js +0 -2
  32. package/lib/Types/Newsletter.d.ts +79 -0
  33. package/lib/Types/Newsletter.js +18 -0
  34. package/lib/Types/Socket.d.ts +8 -3
  35. package/lib/Types/index.d.ts +1 -0
  36. package/lib/Types/index.js +1 -0
  37. package/lib/Utils/auth-utils.d.ts +1 -1
  38. package/lib/Utils/auth-utils.js +3 -4
  39. package/lib/Utils/business.js +15 -3
  40. package/lib/Utils/chat-utils.js +0 -16
  41. package/lib/Utils/crypto.js +6 -4
  42. package/lib/Utils/decode-wa-message.d.ts +5 -3
  43. package/lib/Utils/decode-wa-message.js +158 -31
  44. package/lib/Utils/event-buffer.js +1 -3
  45. package/lib/Utils/generics.d.ts +3 -2
  46. package/lib/Utils/generics.js +16 -36
  47. package/lib/Utils/history.d.ts +2 -2
  48. package/lib/Utils/link-preview.d.ts +1 -1
  49. package/lib/Utils/link-preview.js +1 -24
  50. package/lib/Utils/make-mutex.js +0 -1
  51. package/lib/Utils/messages-media.d.ts +14 -5
  52. package/lib/Utils/messages-media.js +130 -69
  53. package/lib/Utils/messages.d.ts +1 -1
  54. package/lib/Utils/messages.js +309 -57
  55. package/lib/Utils/noise-handler.d.ts +1 -1
  56. package/lib/Utils/process-message.js +0 -1
  57. package/lib/Utils/use-multi-file-auth-state.js +44 -13
  58. package/lib/Utils/validate-connection.js +1 -3
  59. package/lib/WABinary/decode.js +3 -2
  60. package/lib/WABinary/encode.js +13 -5
  61. package/lib/WABinary/generic-utils.d.ts +3 -5
  62. package/lib/WABinary/generic-utils.js +34 -19
  63. package/lib/WABinary/jid-utils.d.ts +12 -3
  64. package/lib/WABinary/jid-utils.js +29 -4
  65. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +21 -12
  66. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +3 -3
  67. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +25 -0
  68. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +53 -0
  69. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +8 -0
  70. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
  71. package/lib/WAUSync/USyncQuery.d.ts +2 -0
  72. package/lib/WAUSync/USyncQuery.js +10 -0
  73. package/lib/WAUSync/USyncUser.d.ts +2 -0
  74. package/lib/WAUSync/USyncUser.js +4 -0
  75. package/lib/index.d.ts +2 -1
  76. package/lib/index.js +3 -1
  77. package/package.json +20 -12
  78. package/WAProto/GenerateStatics.sh +0 -4
  79. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  80. package/lib/Store/make-cache-manager-store.js +0 -83
@@ -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");
@@ -35,6 +35,7 @@ const events_1 = require("events");
35
35
  const fs_1 = require("fs");
36
36
  const os_1 = require("os");
37
37
  const path_1 = require("path");
38
+ const jimp_1 = __importDefault(require("jimp"));
38
39
  const stream_1 = require("stream");
39
40
  const WAProto_1 = require("../../WAProto");
40
41
  const Defaults_1 = require("../Defaults");
@@ -45,11 +46,13 @@ const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
45
46
  const getImageProcessingLibrary = async () => {
46
47
  const [_jimp, sharp] = await Promise.all([
47
48
  (async () => {
48
- const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
49
+ const jimp = await (import('jimp')
50
+ .catch(() => { }));
49
51
  return jimp;
50
52
  })(),
51
53
  (async () => {
52
- const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
54
+ const sharp = await (import('sharp')
55
+ .catch(() => { }));
53
56
  return sharp;
54
57
  })()
55
58
  ]);
@@ -144,8 +147,8 @@ const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
144
147
  .replace(/\=+$/, '')));
145
148
  exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
146
149
  const generateProfilePicture = async (mediaUpload) => {
147
- var _a, _b;
148
150
  let bufferOrFilePath;
151
+ let img;
149
152
  if (Buffer.isBuffer(mediaUpload)) {
150
153
  bufferOrFilePath = mediaUpload;
151
154
  }
@@ -155,29 +158,11 @@ const generateProfilePicture = async (mediaUpload) => {
155
158
  else {
156
159
  bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
157
160
  }
158
- const lib = await getImageProcessingLibrary();
159
- let img;
160
- if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
161
- img = lib.sharp.default(bufferOrFilePath)
162
- .resize(640, 640)
163
- .jpeg({
164
- quality: 50,
165
- })
166
- .toBuffer();
167
- }
168
- else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
169
- const { read, MIME_JPEG, RESIZE_BILINEAR } = lib.jimp;
170
- const jimp = await read(bufferOrFilePath);
171
- const min = Math.min(jimp.getWidth(), jimp.getHeight());
172
- const cropped = jimp.crop(0, 0, min, min);
173
- img = cropped
174
- .quality(50)
175
- .resize(640, 640, RESIZE_BILINEAR)
176
- .getBufferAsync(MIME_JPEG);
177
- }
178
- else {
179
- throw new boom_1.Boom('No image processing library available');
180
- }
161
+ const jimp = await jimp_1.default.read(bufferOrFilePath);
162
+ const cropped = jimp.getWidth() > jimp.getHeight() ? jimp.resize(550, -1) : jimp.resize(-1, 650);
163
+ img = cropped
164
+ .quality(100)
165
+ .getBufferAsync(jimp_1.default.MIME_JPEG);
181
166
  return {
182
167
  img: await img,
183
168
  };
@@ -190,7 +175,7 @@ const mediaMessageSHA256B64 = (message) => {
190
175
  };
191
176
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
192
177
  async function getAudioDuration(buffer) {
193
- const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
178
+ const musicMetadata = await import('music-metadata');
194
179
  let metadata;
195
180
  if (Buffer.isBuffer(buffer)) {
196
181
  metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
@@ -297,7 +282,7 @@ async function generateThumbnail(file, mediaType, options) {
297
282
  }
298
283
  }
299
284
  else if (mediaType === 'video') {
300
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageID)() + '.jpg');
285
+ const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
301
286
  try {
302
287
  await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
303
288
  const buff = await fs_1.promises.readFile(imgFilename);
@@ -319,28 +304,86 @@ const getHttpStream = async (url, options = {}) => {
319
304
  return fetched.data;
320
305
  };
321
306
  exports.getHttpStream = getHttpStream;
307
+ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
308
+ const { stream, type } = await (0, exports.getStream)(media, opts);
309
+ logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
310
+ const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
311
+ const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
312
+ let originalFilePath;
313
+ let didSaveToTmpPath = false;
314
+ let bodyPath;
315
+ try {
316
+ const buffer = await (0, exports.toBuffer)(stream);
317
+ // Write encrypted data
318
+ encFileWriteStream.write(buffer);
319
+ encFileWriteStream.end();
320
+ // Save original file if required
321
+ if (saveOriginalFileIfRequired) {
322
+ originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
323
+ (0, fs_1.writeFileSync)(originalFilePath, buffer);
324
+ bodyPath = originalFilePath;
325
+ didSaveToTmpPath = true;
326
+ }
327
+ else if (type === 'file' && typeof media.url === 'string') {
328
+ bodyPath = media.url;
329
+ }
330
+ const fileLength = buffer.length;
331
+ const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
332
+ stream === null || stream === void 0 ? void 0 : stream.destroy();
333
+ logger === null || logger === void 0 ? void 0 : logger.debug('prepared stream data successfully');
334
+ return {
335
+ mediaKey: undefined,
336
+ encFilePath,
337
+ originalFilePath,
338
+ fileLength,
339
+ fileSha256,
340
+ fileEncSha256: undefined,
341
+ bodyPath,
342
+ didSaveToTmpPath
343
+ };
344
+ }
345
+ catch (error) {
346
+ stream.destroy();
347
+ try {
348
+ await fs_1.promises.unlink(encFilePath);
349
+ }
350
+ catch (_) { }
351
+ if (didSaveToTmpPath && bodyPath) {
352
+ try {
353
+ await fs_1.promises.unlink(bodyPath);
354
+ }
355
+ catch (err) {
356
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to delete tmp bodyPath');
357
+ }
358
+ }
359
+ throw error;
360
+ }
361
+ };
362
+ exports.prepareStream = prepareStream;
322
363
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
364
+ var _a, _b;
323
365
  const { stream, type } = await (0, exports.getStream)(media, opts);
324
366
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
325
367
  const mediaKey = Crypto.randomBytes(32);
326
368
  const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
327
- const encWriteStream = new stream_1.Readable({ read: () => { } });
328
- let bodyPath;
329
- let writeStream;
330
- let didSaveToTmpPath = false;
331
- if (type === 'file') {
332
- bodyPath = media.url.toString();
333
- }
334
- else if (saveOriginalFileIfRequired) {
335
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageID)());
336
- writeStream = (0, fs_1.createWriteStream)(bodyPath);
337
- didSaveToTmpPath = true;
369
+ const encFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-enc');
370
+ const encFileWriteStream = (0, fs_1.createWriteStream)(encFilePath);
371
+ let originalFileStream;
372
+ let originalFilePath;
373
+ if (saveOriginalFileIfRequired) {
374
+ originalFilePath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)() + '-original');
375
+ originalFileStream = (0, fs_1.createWriteStream)(originalFilePath);
338
376
  }
339
377
  let fileLength = 0;
340
378
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
341
379
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
342
380
  let sha256Plain = Crypto.createHash('sha256');
343
381
  let sha256Enc = Crypto.createHash('sha256');
382
+ const onChunk = (buff) => {
383
+ sha256Enc.update(buff);
384
+ hmac.update(buff);
385
+ encFileWriteStream.write(buff);
386
+ };
344
387
  try {
345
388
  for await (const data of stream) {
346
389
  fileLength += data.length;
@@ -351,10 +394,12 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
351
394
  data: { media, type }
352
395
  });
353
396
  }
354
- sha256Plain = sha256Plain.update(data);
355
- if (writeStream && !writeStream.write(data)) {
356
- await (0, events_1.once)(writeStream, 'drain');
397
+ if (originalFileStream) {
398
+ if (!originalFileStream.write(data)) {
399
+ await (0, events_1.once)(originalFileStream, 'drain');
400
+ }
357
401
  }
402
+ sha256Plain.update(data);
358
403
  onChunk(aes.update(data));
359
404
  }
360
405
  onChunk(aes.final());
@@ -362,46 +407,43 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
362
407
  sha256Enc = sha256Enc.update(mac);
363
408
  const fileSha256 = sha256Plain.digest();
364
409
  const fileEncSha256 = sha256Enc.digest();
365
- encWriteStream.push(mac);
366
- encWriteStream.push(null);
367
- writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
410
+ //encWriteStream.push(mac)
411
+ //encWriteStream.push(null)
412
+ encFileWriteStream.write(mac);
413
+ encFileWriteStream.end();
414
+ (_a = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.end) === null || _a === void 0 ? void 0 : _a.call(originalFileStream);
368
415
  stream.destroy();
369
416
  logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
370
417
  return {
371
418
  mediaKey,
372
- encWriteStream,
373
- bodyPath,
419
+ originalFilePath,
420
+ encFilePath,
374
421
  mac,
375
422
  fileEncSha256,
376
423
  fileSha256,
377
- fileLength,
378
- didSaveToTmpPath
424
+ fileLength
379
425
  };
380
426
  }
381
427
  catch (error) {
382
428
  // destroy all streams with error
383
- encWriteStream.destroy();
384
- writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
429
+ encFileWriteStream.destroy();
430
+ (_b = originalFileStream === null || originalFileStream === void 0 ? void 0 : originalFileStream.destroy) === null || _b === void 0 ? void 0 : _b.call(originalFileStream);
385
431
  aes.destroy();
386
432
  hmac.destroy();
387
433
  sha256Plain.destroy();
388
434
  sha256Enc.destroy();
389
435
  stream.destroy();
390
- if (didSaveToTmpPath) {
391
- try {
392
- await fs_1.promises.unlink(bodyPath);
393
- }
394
- catch (err) {
395
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
436
+ try {
437
+ await fs_1.promises.unlink(encFilePath);
438
+ if (originalFilePath) {
439
+ await fs_1.promises.unlink(originalFilePath);
396
440
  }
397
441
  }
442
+ catch (err) {
443
+ logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed deleting tmp files');
444
+ }
398
445
  throw error;
399
446
  }
400
- function onChunk(buff) {
401
- sha256Enc = sha256Enc.update(buff);
402
- hmac = hmac.update(buff);
403
- encWriteStream.push(buff);
404
- }
405
447
  };
406
448
  exports.encryptedStream = encryptedStream;
407
449
  const DEF_HOST = 'mmg.whatsapp.net';
@@ -522,22 +564,36 @@ function extensionForMediaMessage(message) {
522
564
  }
523
565
  exports.extensionForMediaMessage = extensionForMediaMessage;
524
566
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
525
- return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
567
+ return async (filePath, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
526
568
  var _a, _b;
527
569
  // send a query JSON to obtain the url & auth token to upload our media
528
570
  let uploadInfo = await refreshMediaConn(false);
529
571
  let urls;
530
572
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
573
+ /*const chunks: Buffer[] | Buffer = []
574
+ if (!Buffer.isBuffer(stream)) {
575
+ for await (const chunk of stream) {
576
+ chunks.push(chunk)
577
+ }
578
+ }*/
579
+ //const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks)
531
580
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
532
- for (const { hostname } of hosts) {
581
+ let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
582
+ if (newsletter) {
583
+ media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
584
+ }
585
+ for (const { hostname, maxContentLengthBytes } of hosts) {
533
586
  logger.debug(`uploading to "${hostname}"`);
534
587
  const auth = encodeURIComponent(uploadInfo.auth); // the auth token
535
- const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
536
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
588
+ const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
537
589
  let result;
538
590
  try {
539
- const body = await axios_1.default.post(url, stream, {
591
+ //if(maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
592
+ // throw new Boom(`Body too large for "${hostname}"`, { statusCode: 413 })
593
+ //}
594
+ const body = await axios_1.default.post(url, (0, fs_1.createReadStream)(filePath), {
540
595
  ...options,
596
+ maxRedirects: 0,
541
597
  headers: {
542
598
  ...options.headers || {},
543
599
  'Content-Type': 'application/octet-stream',
@@ -553,7 +609,8 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
553
609
  if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
554
610
  urls = {
555
611
  mediaUrl: result.url,
556
- directPath: result.direct_path
612
+ directPath: result.direct_path,
613
+ handle: result.handle
557
614
  };
558
615
  break;
559
616
  }
@@ -665,3 +722,7 @@ const MEDIA_RETRY_STATUS_MAP = {
665
722
  [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
666
723
  [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
667
724
  };
725
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
726
+ function __importStar(arg0) {
727
+ throw new Error('Function not implemented.');
728
+ }
@@ -3,8 +3,8 @@
3
3
  /// <reference types="node" />
4
4
  import { type Transform } from 'stream';
5
5
  import { proto } from '../../WAProto';
6
- import { AnyMediaMessageContent, AnyMessageContent, MediaGenerationOptions, MessageContentGenerationOptions, MessageGenerationOptions, MessageGenerationOptionsFromContent, MessageUserReceipt, WAMessage, WAMessageContent, WAProto } from '../Types';
7
6
  import { ILogger } from './logger';
7
+ import { AnyMediaMessageContent, AnyMessageContent, MediaGenerationOptions, MessageContentGenerationOptions, MessageGenerationOptions, MessageGenerationOptionsFromContent, MessageUserReceipt, WAMessage, WAMessageContent, WAProto } from '../Types';
8
8
  import { MediaDownloadOptions } from './messages-media';
9
9
  /**
10
10
  * Uses a regex to test whether the string contains a URL, and returns the URL if it does.