@rexxhayanasi/elaina-baileys 1.2.0-rc.9 → 1.2.1-rc.1

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
@@ -77,7 +77,9 @@
77
77
  > ❄️ `elaina-baileys` is a refined version of the Baileys library with cleaner API usage, exclusive features like album messaging, newsletter controls, and full-size profile uploads — tailored for modern WhatsApp automation needs.
78
78
 
79
79
  > **Christmas Update** 🎁
80
- > All update information is now redirected to the WhatsApp channel check at the bottom of the "homepage"
80
+ > All update information is now redirected to the WhatsApp channel check at the bottom of the "homepage".
81
+
82
+ > Udpate changelog see on our WhatsApp channel
81
83
 
82
84
  ---
83
85
 
@@ -34,4 +34,3 @@ __exportStar(require("./process-message"), exports);
34
34
  __exportStar(require("./message-retry-manager"), exports);
35
35
  __exportStar(require("./browser-utils"), exports);
36
36
  __exportStar(require("./resolveJid"), exports);
37
- __exportStar(require("./newslettermedia"), exports);
@@ -61,8 +61,6 @@ const Defaults_1 = require("../Defaults");
61
61
  const WABinary_1 = require("../WABinary");
62
62
  const crypto_1 = require("./crypto");
63
63
  const generics_1 = require("./generics");
64
- const toAsyncIterable_1 = require("./async-iterable");
65
-
66
64
  const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
67
65
  const getImageProcessingLibrary = async () => {
68
66
  const [_jimp, sharp] = await Promise.all([
@@ -78,27 +76,64 @@ const getImageProcessingLibrary = async () => {
78
76
  if (sharp) {
79
77
  return { sharp };
80
78
  }
81
- const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
79
+ const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
82
80
  if (jimp) {
83
81
  return { jimp };
84
82
  }
85
83
  throw new boom_1.Boom('No image processing library available');
86
84
  };
87
-
88
85
  const hkdfInfoKey = (type) => {
89
- if (type === 'sticker-pack') return 'WhatsApp Image Keys';
90
- if (type === 'ptv') return 'WhatsApp Video Keys';
91
- if (type === 'newsletter-image') return 'WhatsApp Image Keys';
92
- if (type === 'newsletter-video') return 'WhatsApp Video Keys';
93
-
94
86
  const hkdfInfo = Defaults_1.MEDIA_HKDF_KEY_MAPPING[type];
95
- if (!hkdfInfo) {
96
- return 'WhatsApp Image Keys';
97
- }
98
87
  return `WhatsApp ${hkdfInfo} Keys`;
99
88
  };
100
89
  exports.hkdfInfoKey = hkdfInfoKey;
101
90
 
91
+ const getRawMediaUploadData = async (media, mediaType, logger) => {
92
+
93
+ const { stream } = await exports.getStream(media);
94
+ logger === null || logger === void 0 ? void 0 : logger.debug('got stream for raw upload');
95
+ const hasher = Crypto.createHash('sha256');
96
+
97
+ // Generate file temp
98
+ const filePath = (0, path_1.join)((0, os_1.tmpdir)(), mediaType + (0, generics_1.generateMessageIDV2)());
99
+ const fileWriteStream = (0, fs_1.createWriteStream)(filePath);
100
+
101
+ let fileLength = 0;
102
+ try {
103
+ for await (const data of stream) {
104
+ fileLength += data.length;
105
+ hasher.update(data);
106
+ // Handle backpressure
107
+ if (!fileWriteStream.write(data)) {
108
+ await (0, events_1.once)(fileWriteStream, 'drain');
109
+ }
110
+ }
111
+ fileWriteStream.end();
112
+ await (0, events_1.once)(fileWriteStream, 'finish');
113
+ stream.destroy();
114
+
115
+ const fileSha256 = hasher.digest();
116
+ logger === null || logger === void 0 ? void 0 : logger.debug('hashed data for raw upload');
117
+
118
+ return {
119
+ filePath: filePath,
120
+ fileSha256,
121
+ fileLength
122
+ };
123
+ }
124
+ catch (error) {
125
+ fileWriteStream.destroy();
126
+ stream.destroy();
127
+ try {
128
+ await fs_1.promises.unlink(filePath);
129
+ }
130
+ catch (_a) {
131
+ // ignore
132
+ }
133
+ throw error;
134
+ }
135
+ };
136
+ exports.getRawMediaUploadData = getRawMediaUploadData;
102
137
  /** generates all the keys required to encrypt/decrypt & sign a media message */
103
138
  async function getMediaKeys(buffer, mediaType) {
104
139
  if (!buffer) {
@@ -115,7 +150,6 @@ async function getMediaKeys(buffer, mediaType) {
115
150
  macKey: expandedMediaKey.slice(48, 80),
116
151
  };
117
152
  }
118
-
119
153
  async function uploadFile(buffer, logger) {
120
154
  const { fromBuffer } = await Promise.resolve().then(() => __importStar(require('file-type')));
121
155
  const fileType = await fromBuffer(buffer);
@@ -220,7 +254,6 @@ async function uploadFile(buffer, logger) {
220
254
  }
221
255
  throw new Error("All upload services failed.");
222
256
  }
223
-
224
257
  async function vid2jpg(videoUrl) {
225
258
  try {
226
259
  const { data } = await axios_1.default.get(`https://ezgif.com/video-to-jpg?url=${encodeURIComponent(videoUrl)}`);
@@ -257,7 +290,6 @@ async function vid2jpg(videoUrl) {
257
290
  throw new Error("Failed to convert video to JPG: " + error.message);
258
291
  }
259
292
  }
260
-
261
293
  /**
262
294
  * Extracts video thumbnail using FFmpeg
263
295
  */
@@ -288,7 +320,6 @@ const extractVideoThumb = async (videoPath, time = '00:00:00', size = { width: 2
288
320
  });
289
321
  };
290
322
  exports.extractVideoThumb = extractVideoThumb;
291
-
292
323
  const extractImageThumb = async (bufferOrFilePath, width = 32) => {
293
324
  var _a, _b;
294
325
  if (bufferOrFilePath instanceof stream_1.Readable) {
@@ -331,13 +362,11 @@ const extractImageThumb = async (bufferOrFilePath, width = 32) => {
331
362
  }
332
363
  };
333
364
  exports.extractImageThumb = extractImageThumb;
334
-
335
365
  const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
336
366
  .replace(/\+/g, '-')
337
367
  .replace(/\//g, '_')
338
368
  .replace(/\=+$/, '')));
339
369
  exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
340
-
341
370
  const generateProfilePicture = async (mediaUpload) => {
342
371
  let bufferOrFilePath;
343
372
  let img;
@@ -360,14 +389,12 @@ const generateProfilePicture = async (mediaUpload) => {
360
389
  };
361
390
  };
362
391
  exports.generateProfilePicture = generateProfilePicture;
363
-
364
392
  /** gets the SHA256 of the given media message */
365
393
  const mediaMessageSHA256B64 = (message) => {
366
394
  const media = Object.values(message)[0];
367
395
  return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
368
396
  };
369
397
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
370
-
371
398
  async function getAudioDuration(buffer) {
372
399
  const musicMetadata = await Promise.resolve().then(() => __importStar(require('music-metadata')));
373
400
  let metadata;
@@ -385,7 +412,6 @@ async function getAudioDuration(buffer) {
385
412
  }
386
413
  return metadata.format.duration;
387
414
  }
388
-
389
415
  async function getAudioWaveform(buffer, logger) {
390
416
  try {
391
417
  const { default: decoder } = await eval('import(\'audio-decode\')');
@@ -422,7 +448,6 @@ async function getAudioWaveform(buffer, logger) {
422
448
  logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
423
449
  }
424
450
  }
425
-
426
451
  const toReadable = (buffer) => {
427
452
  const readable = new stream_1.Readable({ read: () => { } });
428
453
  readable.push(buffer);
@@ -430,7 +455,6 @@ const toReadable = (buffer) => {
430
455
  return readable;
431
456
  };
432
457
  exports.toReadable = toReadable;
433
-
434
458
  const toBuffer = async (stream) => {
435
459
  const chunks = [];
436
460
  for await (const chunk of stream) {
@@ -440,7 +464,6 @@ const toBuffer = async (stream) => {
440
464
  return Buffer.concat(chunks);
441
465
  };
442
466
  exports.toBuffer = toBuffer;
443
-
444
467
  const getStream = async (item, opts) => {
445
468
  if (Buffer.isBuffer(item)) {
446
469
  return { stream: (0, exports.toReadable)(item), type: 'buffer' };
@@ -454,7 +477,6 @@ const getStream = async (item, opts) => {
454
477
  return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
455
478
  };
456
479
  exports.getStream = getStream;
457
-
458
480
  /** generates a thumbnail for a given media, if required */
459
481
  async function generateThumbnail(file, mediaType, options) {
460
482
  var _a;
@@ -503,13 +525,11 @@ async function generateThumbnail(file, mediaType, options) {
503
525
  originalImageDimensions
504
526
  };
505
527
  }
506
-
507
528
  const getHttpStream = async (url, options = {}) => {
508
529
  const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
509
530
  return fetched.data;
510
531
  };
511
532
  exports.getHttpStream = getHttpStream;
512
-
513
533
  const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
514
534
  const { stream, type } = await (0, exports.getStream)(media, opts);
515
535
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
@@ -553,7 +573,6 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
553
573
  }
554
574
  };
555
575
  exports.prepareStream = prepareStream;
556
-
557
576
  const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
558
577
  const { stream, type } = await (0, exports.getStream)(media, opts);
559
578
  logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
@@ -640,7 +659,6 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
640
659
  }
641
660
  };
642
661
  exports.encryptedStream = encryptedStream;
643
-
644
662
  const DEF_HOST = 'mmg.whatsapp.net';
645
663
  const AES_CHUNK_SIZE = 16;
646
664
  const toSmallestChunkSize = (num) => {
@@ -648,7 +666,6 @@ const toSmallestChunkSize = (num) => {
648
666
  };
649
667
  const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
650
668
  exports.getUrlFromDirectPath = getUrlFromDirectPath;
651
-
652
669
  const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
653
670
  const isValidMediaUrl = url === null || url === void 0 ? void 0 : url.startsWith('https://mmg.whatsapp.net/');
654
671
  const downloadUrl = isValidMediaUrl ? url : (0, exports.getUrlFromDirectPath)(directPath);
@@ -659,7 +676,6 @@ const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, o
659
676
  return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
660
677
  };
661
678
  exports.downloadContentFromMessage = downloadContentFromMessage;
662
-
663
679
  const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
664
680
  let bytesFetched = 0;
665
681
  let startChunk = 0;
@@ -740,7 +756,6 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
740
756
  return fetched.pipe(output, { end: true });
741
757
  };
742
758
  exports.downloadEncryptedContent = downloadEncryptedContent;
743
-
744
759
  function extensionForMediaMessage(message) {
745
760
  const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
746
761
  const type = Object.keys(message)[0];
@@ -756,7 +771,6 @@ function extensionForMediaMessage(message) {
756
771
  }
757
772
  return extension;
758
773
  }
759
-
760
774
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
761
775
  return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
762
776
  var _a, _b;
@@ -764,14 +778,6 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
764
778
  let urls;
765
779
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
766
780
  const chunks = [];
767
-
768
- try {
769
- stream = toAsyncIterable_1.toAsyncIterable(stream);
770
- } catch (error) {
771
- throw new boom_1.Boom(error.message, { statusCode: 400 });
772
- }
773
- // --------------------------------------------------------
774
-
775
781
  if (!Buffer.isBuffer(stream)) {
776
782
  for await (const chunk of stream) {
777
783
  chunks.push(chunk);
@@ -779,20 +785,10 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
779
785
  }
780
786
  const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
781
787
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
782
-
783
788
  let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
784
- if (mediaType === 'sticker-pack') {
785
- media = '/mms/image';
786
- }
787
-
788
789
  if (newsletter) {
789
- if (media) {
790
- media = media.replace('/mms/', '/newsletter/newsletter-');
791
- } else {
792
- media = '/newsletter/newsletter-image';
793
- }
790
+ media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
794
791
  }
795
-
796
792
  for (const { hostname, maxContentLengthBytes } of hosts) {
797
793
  logger.debug(`uploading to "${hostname}"`);
798
794
  const auth = encodeURIComponent(uploadInfo.auth);
@@ -843,8 +839,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
843
839
  return urls;
844
840
  };
845
841
  };
846
- exports.getWAUploadToServer = getWAUploadToServer;
847
-
842
+ exports.getWAUploadToServer = getWAUploadToServer;
848
843
  const getMediaRetryKey = (mediaKey) => {
849
844
  return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
850
845
  };
@@ -883,7 +878,6 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
883
878
  return req;
884
879
  };
885
880
  exports.encryptMediaRetryRequest = encryptMediaRetryRequest;
886
-
887
881
  const decodeMediaRetryNode = (node) => {
888
882
  const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
889
883
  const event = {
@@ -913,17 +907,14 @@ const decodeMediaRetryNode = (node) => {
913
907
  return event;
914
908
  };
915
909
  exports.decodeMediaRetryNode = decodeMediaRetryNode;
916
-
917
910
  const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
918
911
  const retryKey = await getMediaRetryKey(mediaKey);
919
912
  const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
920
913
  return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
921
914
  };
922
915
  exports.decryptMediaRetryData = decryptMediaRetryData;
923
-
924
916
  const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
925
917
  exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
926
-
927
918
  const MEDIA_RETRY_STATUS_MAP = {
928
919
  [WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
929
920
  [WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
@@ -2,29 +2,11 @@
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
- Object.defineProperty(exports, "__esModule", { value: true })
6
- const getImageProcessingLibrary = async () => {
7
- const lib = {};
8
- try {
9
- lib.sharp = require('sharp');
10
- } catch {}
11
- try {
12
- lib.jimp = require('jimp');
13
- } catch {}
14
- return lib;
15
- };
16
- const isWebPBuffer = (buffer) => {
17
- return buffer.length >= 12 && buffer.toString('ascii', 8, 12) === 'WEBP';
18
- };
19
- const isAnimatedWebP = (buffer) => {
20
- if (!isWebPBuffer(buffer)) return false;
21
- return buffer.includes(Buffer.from("ANIM"));
22
- };
23
- exports.prepareStickerPackMessage = exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
24
7
  exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
25
8
  const boom_1 = require("@hapi/boom");
26
9
  const axios_1 = __importDefault(require("axios"));
27
- const fflate_1 = require("fflate");
28
10
  const crypto_1 = require("crypto");
29
11
  const fs_1 = require("fs");
30
12
  const WAProto_1 = require("../../WAProto");
@@ -41,10 +23,6 @@ const MIMETYPE_MAP = {
41
23
  audio: 'audio/ogg; codecs=opus',
42
24
  sticker: 'image/webp',
43
25
  'product-catalog-image': 'image/jpeg',
44
- 'sticker-pack': 'application/x-zip-compressed',
45
- "ptv": "video/mp4",
46
- "newsletter-image": "image/jpeg",
47
- "newsletter-video": "video/mp4"
48
26
  };
49
27
  const MessageTypeProto = {
50
28
  'image': Types_1.WAProto.Message.ImageMessage,
@@ -88,53 +66,36 @@ const assertColor = async (color) => {
88
66
  return assertedColor;
89
67
  }
90
68
  };
91
- const prepareWAMessageMedia = async (message, options) => {
69
+ const prepareWAMessageMedia = async (message, options) => {
92
70
  const logger = options.logger;
93
71
  let mediaType;
94
-
95
72
  for (const key of Defaults_1.MEDIA_KEYS) {
96
73
  if (key in message) {
97
74
  mediaType = key;
98
75
  }
99
76
  }
100
-
101
- if (!mediaType && 'ptv' in message) {
102
- mediaType = 'ptv';
103
- }
104
-
105
77
  if (!mediaType) {
106
78
  throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
107
79
  }
108
-
109
- let isPtv = false;
110
- if (mediaType === 'ptv') {
111
- isPtv = true;
112
- mediaType = 'video';
113
- }
114
-
115
80
  const uploadData = {
116
81
  ...message,
117
- media: message[mediaType] || message['ptv']
82
+ media: message[mediaType]
118
83
  };
119
-
120
- if (!(mediaType === 'audio' && uploadData.ptt)) {
121
84
  delete uploadData[mediaType];
122
- }
123
- delete uploadData['ptv'];
124
-
85
+
86
+ // Check cache
125
87
  const cacheableKey = typeof uploadData.media === 'object' &&
126
88
  ('url' in uploadData.media) &&
127
89
  !!uploadData.media.url &&
128
- !!options.mediaCache && (
129
- mediaType + ':' + uploadData.media.url.toString());
130
-
90
+ !!options.mediaCache && (mediaType + ':' + uploadData.media.url.toString());
91
+
131
92
  if (mediaType === 'document' && !uploadData.fileName) {
132
93
  uploadData.fileName = 'file';
133
94
  }
134
95
  if (!uploadData.mimetype) {
135
96
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
136
97
  }
137
-
98
+
138
99
  if (cacheableKey) {
139
100
  const mediaBuff = options.mediaCache.get(cacheableKey);
140
101
  if (mediaBuff) {
@@ -146,35 +107,35 @@ const assertColor = async (color) => {
146
107
  }
147
108
  }
148
109
 
149
- const isNewsletter = options.newsletter || (options.jid && (0, WABinary_1.isJidNewsletter)(options.jid));
150
- if (isNewsletter) {
151
- logger === null || logger === void 0 ? void 0 : logger.debug({ key: cacheableKey }, 'Preparing raw media for newsletter');
152
-
110
+ // --- [MULAI] LOGIKA KHUSUS NEWSLETTER (WHISKEYSOCKETS ADAPTATION) ---
111
+ const isNewsletter = !!options.jid && (0, WABinary_1.isJidNewsletter)(options.jid);
153
112
 
154
- const { bodyPath, fileSha256, fileLength, didSaveToTmpPath, encWriteStream } = await (0, messages_media_1.prepareStream)(
113
+ if (isNewsletter) {
114
+ logger === null || logger === void 0 ? void 0 : logger.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
115
+
116
+ // 1. Dapatkan file mentah (RAW) menggunakan fungsi yang baru kita buat di messages-media.js
117
+ const { filePath, fileSha256, fileLength } = await (0, messages_media_1.getRawMediaUploadData)(
155
118
  uploadData.media,
156
119
  options.mediaTypeOverride || mediaType,
157
- { logger, opts: options.options }
120
+ logger
158
121
  );
159
122
 
160
- const fileEncSha256B64 = fileSha256.toString('base64');
161
- const streamToUpload = bodyPath || encWriteStream;
162
-
123
+ const fileSha256B64 = fileSha256.toString('base64');
124
+
125
+ // 2. Upload Stream Mentah
126
+ // Kita buat ReadStream dari filePath agar kompatibel dengan sistem upload Baileys v6
127
+ const streamToUpload = (0, fs_1.createReadStream)(filePath);
128
+
163
129
  const { mediaUrl, directPath } = await options.upload(streamToUpload, {
164
- fileEncSha256B64,
165
- mediaType,
166
- timeoutMs: options.mediaUploadTimeoutMs,
167
- newsletter: true
130
+ fileEncSha256B64: fileSha256B64,
131
+ mediaType: mediaType,
132
+ timeoutMs: options.mediaUploadTimeoutMs
168
133
  });
169
134
 
170
- if (didSaveToTmpPath && bodyPath) {
171
- try {
172
- await fs_1.promises.unlink(bodyPath);
173
- } catch (error) {
174
- logger === null || logger === void 0 ? void 0 : logger.warn('failed to remove tmp file');
175
- }
176
- }
135
+ // Hapus file temp setelah upload selesai
136
+ await fs_1.promises.unlink(filePath);
177
137
 
138
+ // 3. Buat Objek Pesan
178
139
  const obj = Types_1.WAProto.Message.fromObject({
179
140
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
180
141
  url: mediaUrl,
@@ -186,15 +147,13 @@ const assertColor = async (color) => {
186
147
  })
187
148
  });
188
149
 
189
- if (mediaType === 'audio' && uploadData.ptt) {
190
- obj.audioMessage.ptt = true;
191
- }
192
-
193
- if (isPtv) {
150
+ // 4. Ubah tipe pesan jadi PTV jika flag aktif
151
+ if (uploadData.ptv) {
194
152
  obj.ptvMessage = obj.videoMessage;
195
153
  delete obj.videoMessage;
196
154
  }
197
155
 
156
+ // Handle sticker timestamp
198
157
  if (obj.stickerMessage) {
199
158
  obj.stickerMessage.stickerSentTs = Date.now();
200
159
  }
@@ -206,30 +165,29 @@ const assertColor = async (color) => {
206
165
 
207
166
  return obj;
208
167
  }
168
+ // --- [SELESAI] LOGIKA NEWSLETTER ---
169
+
209
170
 
171
+ // --- LOGIKA LAMA (E2E / CHAT BIASA) ---
210
172
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
211
173
  const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
212
174
  (typeof uploadData['jpegThumbnail'] === 'undefined');
213
175
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
214
176
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
215
177
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
216
-
178
+
179
+ // Enkripsi standar
217
180
  const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (0, messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
218
181
  logger,
219
182
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
220
183
  opts: options.options
221
184
  });
222
-
185
+
223
186
  const fileEncSha256B64 = (fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
224
-
187
+
225
188
  const [{ mediaUrl, directPath, handle }] = await Promise.all([
226
189
  (async () => {
227
- const result = await options.upload(encWriteStream, {
228
- fileEncSha256B64,
229
- mediaType,
230
- timeoutMs: options.mediaUploadTimeoutMs,
231
- newsletter: false
232
- });
190
+ const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
233
191
  logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
234
192
  return result;
235
193
  })(),
@@ -241,16 +199,21 @@ const assertColor = async (color) => {
241
199
  if (!uploadData.width && originalImageDimensions) {
242
200
  uploadData.width = originalImageDimensions.width;
243
201
  uploadData.height = originalImageDimensions.height;
202
+ logger === null || logger === void 0 ? void 0 : logger.debug('set dimensions');
244
203
  }
204
+ logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
245
205
  }
246
206
  if (requiresDurationComputation) {
247
207
  uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
208
+ logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
248
209
  }
249
210
  if (requiresWaveformProcessing) {
250
211
  uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
212
+ logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
251
213
  }
252
214
  if (requiresAudioBackground) {
253
215
  uploadData.backgroundArgb = await assertColor(options.backgroundColor);
216
+ logger === null || logger === void 0 ? void 0 : logger.debug('computed backgroundColor audio status');
254
217
  }
255
218
  }
256
219
  catch (error) {
@@ -258,10 +221,11 @@ const assertColor = async (color) => {
258
221
  }
259
222
  })(),
260
223
  ])
261
- .finally(async () => {
224
+ .finally(async () => {
262
225
  if (!Buffer.isBuffer(encWriteStream)) {
263
226
  encWriteStream.destroy();
264
227
  }
228
+ // remove tmp files
265
229
  if (didSaveToTmpPath && bodyPath) {
266
230
  try {
267
231
  await fs_1.promises.access(bodyPath);
@@ -273,7 +237,7 @@ const assertColor = async (color) => {
273
237
  }
274
238
  }
275
239
  });
276
-
240
+
277
241
  const obj = Types_1.WAProto.Message.fromObject({
278
242
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
279
243
  url: handle ? undefined : mediaUrl,
@@ -287,20 +251,19 @@ const assertColor = async (color) => {
287
251
  media: undefined
288
252
  })
289
253
  });
290
-
291
- if (isPtv) {
254
+
255
+ if (uploadData.ptv) {
292
256
  obj.ptvMessage = obj.videoMessage;
293
257
  delete obj.videoMessage;
294
258
  }
295
-
259
+
296
260
  if (cacheableKey) {
261
+ logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
297
262
  options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
298
263
  }
299
264
  return obj;
300
265
  };
301
266
  exports.prepareWAMessageMedia = prepareWAMessageMedia;
302
-
303
-
304
267
  const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
305
268
  ephemeralExpiration = ephemeralExpiration || 0;
306
269
  const content = {
@@ -484,11 +447,9 @@ const generateWAMessageContent = async (message, options) => {
484
447
  break;
485
448
  }
486
449
  }
487
- else if ('ptv' in message && message.ptv) {
488
- const generated = await (0, exports.prepareWAMessageMedia)({
489
- ptv: message.ptv
490
- }, options);
491
- m.ptvMessage = generated.ptvMessage || generated.videoMessage;
450
+ else if ('ptv' in message && message.ptv) {
451
+ const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
452
+ m.ptvMessage = videoMessage;
492
453
  }
493
454
  else if ('product' in message) {
494
455
  const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
@@ -1145,170 +1106,3 @@ const getSenderLid = (message) => {
1145
1106
  return { jid: sender, lid };
1146
1107
  };
1147
1108
  exports.getSenderLid = getSenderLid;
1148
-
1149
- /**
1150
- STICKER PACK FUNCTION RECODE BY
1151
- @RexxHayanasi < Maintainer @rexxhayanasi/elaina-baileys >
1152
- **/
1153
-
1154
- const prepareStickerPackMessage = async (stickerPack, options) => {
1155
- const { stickers, name, publisher, packId, description } = stickerPack;
1156
-
1157
- if (stickers.length > 60) {
1158
- throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
1159
- }
1160
-
1161
- if (stickers.length === 0) {
1162
- throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
1163
- }
1164
-
1165
- const stickerPackIdValue = packId || (0, generics_1.generateMessageIDV2)();
1166
- const lib = await getImageProcessingLibrary();
1167
- const stickerData = {};
1168
-
1169
- const stickerPromises = stickers.map(async (s, i) => {
1170
- const { stream } = await (0, messages_media_1.getStream)(s.data);
1171
- const buffer = await (0, generics_1.toBuffer)(stream);
1172
-
1173
- let webpBuffer;
1174
- let isAnimated = false;
1175
- const isWebP = isWebPBuffer(buffer);
1176
-
1177
- if (isWebP) {
1178
- webpBuffer = buffer;
1179
- isAnimated = isAnimatedWebP(buffer);
1180
- } else if (lib.sharp) {
1181
- webpBuffer = await lib.sharp(buffer).webp().toBuffer();
1182
- isAnimated = false;
1183
- } else {
1184
- throw new boom_1.Boom(
1185
- 'No image processing library (sharp) available for converting sticker to WebP. Either install sharp or provide stickers in WebP format.'
1186
- );
1187
- }
1188
-
1189
- if (webpBuffer.length > 1024 * 1024) {
1190
- throw new boom_1.Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
1191
- }
1192
-
1193
- const hash = (0, crypto_2.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
1194
- const fileName = `${hash}.webp`;
1195
-
1196
- stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
1197
-
1198
- return {
1199
- fileName,
1200
- mimetype: 'image/webp',
1201
- isAnimated,
1202
- emojis: s.emojis || [],
1203
- accessibilityLabel: s.accessibilityLabel
1204
- };
1205
- });
1206
-
1207
- const stickerMetadata = await Promise.all(stickerPromises);
1208
-
1209
- const trayIconFileName = `${stickerPackIdValue}.webp`;
1210
- const { stream: coverStream } = await (0, messages_media_1.getStream)(stickerPack.cover);
1211
- const coverBuffer = await (0, generics_1.toBuffer)(coverStream);
1212
-
1213
- let coverWebpBuffer;
1214
- const isCoverWebP = isWebPBuffer(coverBuffer);
1215
-
1216
- if (isCoverWebP) {
1217
- coverWebpBuffer = coverBuffer;
1218
- } else if (lib.sharp) {
1219
- coverWebpBuffer = await lib.sharp(coverBuffer).webp().toBuffer();
1220
- } else {
1221
- throw new boom_1.Boom(
1222
- 'No image processing library (sharp) available for converting cover to WebP. Either install sharp or provide cover in WebP format.'
1223
- );
1224
- }
1225
-
1226
- stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
1227
-
1228
- const zipBuffer = await new Promise((resolve, reject) => {
1229
- (0, fflate_1.zip)(stickerData, (err, data) => {
1230
- if (err) {
1231
- reject(err);
1232
- } else {
1233
- resolve(Buffer.from(data));
1234
- }
1235
- });
1236
- });
1237
-
1238
- const stickerPackSize = zipBuffer.length;
1239
-
1240
- const stickerPackUpload = await (0, messages_media_1.encryptedStream)(zipBuffer, 'sticker-pack', {
1241
- logger: options.logger,
1242
- opts: options.options
1243
- });
1244
-
1245
- const stickerPackUploadResult = await options.upload(stickerPackUpload.encFilePath, {
1246
- fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
1247
- mediaType: 'sticker-pack',
1248
- timeoutMs: options.mediaUploadTimeoutMs
1249
- });
1250
-
1251
- await fs_1.promises.unlink(stickerPackUpload.encFilePath);
1252
-
1253
- const stickerPackMessage = {
1254
- name: name,
1255
- publisher: publisher,
1256
- stickerPackId: stickerPackIdValue,
1257
- packDescription: description,
1258
- stickerPackOrigin: WAProto_1.proto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED,
1259
- stickerPackSize: stickerPackSize,
1260
- stickers: stickerMetadata,
1261
- fileSha256: stickerPackUpload.fileSha256,
1262
- fileEncSha256: stickerPackUpload.fileEncSha256,
1263
- mediaKey: stickerPackUpload.mediaKey,
1264
- directPath: stickerPackUploadResult.directPath,
1265
- fileLength: stickerPackUpload.fileLength,
1266
- mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
1267
- trayIconFileName: trayIconFileName
1268
- };
1269
-
1270
- try {
1271
- let thumbnailBuffer;
1272
- if (lib.sharp) {
1273
- thumbnailBuffer = await lib.sharp(coverBuffer).resize(252, 252).jpeg().toBuffer();
1274
- } else if (lib.jimp) {
1275
- const jimpImage = await lib.jimp.read(coverBuffer);
1276
- thumbnailBuffer = await jimpImage.resize(252, 252).getBufferAsync(lib.jimp.MIME_JPEG);
1277
- } else {
1278
- throw new Error('No image processing library available for thumbnail generation');
1279
- }
1280
-
1281
- if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
1282
- throw new Error('Failed to generate thumbnail buffer');
1283
- }
1284
-
1285
- const thumbUpload = await (0, messages_media_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
1286
- logger: options.logger,
1287
- opts: options.options,
1288
- mediaKey: stickerPackUpload.mediaKey
1289
- });
1290
-
1291
- const thumbUploadResult = await options.upload(thumbUpload.encFilePath, {
1292
- fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
1293
- mediaType: 'thumbnail-sticker-pack',
1294
- timeoutMs: options.mediaUploadTimeoutMs
1295
- });
1296
-
1297
- await fs_1.promises.unlink(thumbUpload.encFilePath);
1298
-
1299
- Object.assign(stickerPackMessage, {
1300
- thumbnailDirectPath: thumbUploadResult.directPath,
1301
- thumbnailSha256: thumbUpload.fileSha256,
1302
- thumbnailEncSha256: thumbUpload.fileEncSha256,
1303
- thumbnailHeight: 252,
1304
- thumbnailWidth: 252,
1305
- imageDataHash: (0, crypto_2.sha256)(thumbnailBuffer).toString('base64')
1306
- });
1307
-
1308
- } catch (e) {
1309
- options.logger === null || options.logger === void 0 ? void 0 : options.logger.warn(`Thumbnail generation failed: ${e}`);
1310
- }
1311
-
1312
- return { stickerPackMessage };
1313
- };
1314
- exports.prepareStickerPackMessage = prepareStickerPackMessage;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rexxhayanasi/elaina-baileys",
3
- "version": "1.2.0-rc.9",
3
+ "version": "1.2.1-rc.1",
4
4
  "description": "Custom Baileys WhatsApp API",
5
5
  "keywords": [
6
6
  "baileys",
@@ -18,7 +18,7 @@
18
18
  "homepage": "https://whatsapp.com/channel/0029Vb70uHbD8SE2w5Q9M107",
19
19
  "license": "MIT",
20
20
  "publishConfig": {
21
- "tag": "experimental"
21
+ "tag": "latest"
22
22
  },
23
23
  "author": "RexxHayanasi",
24
24
  "main": "lib/index.js",
@@ -1,110 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.getWAUploadToServerNewsletter = exports.prepareWAMessageMediaNewsletter = exports.getRawMediaUploadDataNewsletter = void 0;
5
-
6
- const crypto_1 = require("crypto");
7
- const boom_1 = require("@hapi/boom");
8
- const WAProto_1 = require("../../WAProto");
9
- const axios_1 = require("axios");
10
- const Defaults_1 = require("../Defaults");
11
-
12
- function getRawMediaUploadDataNewsletter(buffer) {
13
- if (!Buffer.isBuffer(buffer)) {
14
- throw new boom_1.Boom("Newsletter media must be Buffer");
15
- }
16
- const fileSha256 = (0, crypto_1.createHash)("sha256").update(buffer).digest();
17
- return {
18
- buffer,
19
- fileSha256,
20
- fileLength: buffer.length
21
- };
22
- }
23
- exports.getRawMediaUploadDataNewsletter = getRawMediaUploadDataNewsletter;
24
-
25
- function getWAUploadToServerNewsletter({ customUploadHosts = [], fetchAgent, logger, options = {} }, refreshMediaConn) {
26
- return async (buffer, { mediaType, fileEncSha256B64 }) => {
27
- if (!Buffer.isBuffer(buffer)) {
28
- throw new boom_1.Boom("Upload expects Buffer");
29
- }
30
- let uploadInfo = await refreshMediaConn(false);
31
- const hosts = [...customUploadHosts, ...uploadInfo.hosts];
32
- let urls;
33
- for (const { hostname, maxContentLengthBytes } of hosts) {
34
- const auth = encodeURIComponent(uploadInfo.auth);
35
- let mediaPath = Defaults_1.MEDIA_PATH_MAP[mediaType];
36
- if (!mediaPath) {
37
- mediaPath = "/newsletter/newsletter-image";
38
- } else {
39
- mediaPath = mediaPath.replace("/mms/", "/newsletter/newsletter-");
40
- }
41
- const url = `https://${hostname}${mediaPath}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
42
- try {
43
- if (maxContentLengthBytes && buffer.length > maxContentLengthBytes) {
44
- throw new boom_1.Boom("Body too large", { statusCode: 413 });
45
- }
46
- const res = await axios_1.default.post(url, buffer, {
47
- ...options,
48
- headers: {
49
- "Content-Type": "application/octet-stream",
50
- Origin: Defaults_1.DEFAULT_ORIGIN,
51
- ...(options.headers || {})
52
- },
53
- httpsAgent: fetchAgent,
54
- responseType: "json",
55
- maxBodyLength: Infinity,
56
- maxContentLength: Infinity
57
- });
58
- const result = res.data;
59
- if (result?.url || result?.direct_path) {
60
- urls = {
61
- mediaUrl: result.url,
62
- directPath: result.direct_path
63
- };
64
- break;
65
- }
66
- uploadInfo = await refreshMediaConn(true);
67
- } catch (err) {
68
- logger?.warn?.({ err }, `Newsletter upload failed on ${hostname}`);
69
- }
70
- }
71
- if (!urls) {
72
- throw new boom_1.Boom("Newsletter media upload failed", { statusCode: 500 });
73
- }
74
- return urls;
75
- };
76
- }
77
- exports.getWAUploadToServerNewsletter = getWAUploadToServerNewsletter;
78
-
79
- async function prepareWAMessageMediaNewsletter(message, options) {
80
- if (!options || typeof options.upload !== "function") {
81
- throw new boom_1.Boom("upload function is required");
82
- }
83
- const mediaType = Object.keys(message || {})[0];
84
- if (!mediaType) {
85
- throw new boom_1.Boom("Invalid newsletter media");
86
- }
87
- const buffer = message[mediaType];
88
- if (!Buffer.isBuffer(buffer)) {
89
- throw new boom_1.Boom("Newsletter media must be Buffer");
90
- }
91
- const uploadData = getRawMediaUploadDataNewsletter(buffer);
92
- const uploaded = await options.upload(buffer, {
93
- mediaType,
94
- fileEncSha256B64: uploadData.fileSha256.toString("base64"),
95
- newsletter: true
96
- });
97
- const proto = {};
98
- proto[`${mediaType}Message`] = {
99
- url: uploaded.mediaUrl,
100
- directPath: uploaded.directPath,
101
- fileSha256: uploadData.fileSha256,
102
- fileLength: uploadData.fileLength,
103
- mimetype: options.mimetype
104
- };
105
- if (mediaType === "video") {
106
- proto.videoMessage.ptv = true;
107
- }
108
- return WAProto_1.WAProto.Message.fromObject(proto);
109
- }
110
- exports.prepareWAMessageMediaNewsletter = prepareWAMessageMediaNewsletter;