@itsliaaa/baileys 0.1.28 โ†’ 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
@@ -41,10 +41,9 @@ Hi everyone,
41
41
  >
42
42
  > Recently, I found a few packages published on npm that are essentially just **renamed** versions of a fork I personally worked on:
43
43
  >
44
- > - https://www.npmjs.com/package/@noya4u_27/baileys
45
- > - https://www.npmjs.com/package/@phrolovaa/baileys
46
- > - https://www.npmjs.com/package/@dnuzi/baileys
47
- > - https://www.npmjs.com/package/@crysnovax/baileys
44
+ > - [@noya4u_27](https://www.npmjs.com/package/@noya4u_27/baileys) **[STEALER]**
45
+ > - [@phrolovaa](https://www.npmjs.com/package/@phrolovaa/baileys) **[STEALER]**
46
+ > - [@dnuzi](https://www.npmjs.com/package/@dnuzi/baileys) **[STEALER]**
48
47
  >
49
48
  > To be clear, Iโ€™m **not** the original maintainer of Baileys all respect goes to the amazing work behind [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys). I only created and maintained my own fork ([@itsliaaa/baileys](https://www.npmjs.com/package/@itsliaaa/baileys)) where I spent a **lot** of time improving and adapting things on my own.
50
49
  >
@@ -383,6 +382,28 @@ sock.sendMessage(jid, {
383
382
  })
384
383
  ```
385
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
+
386
407
  #### ๐Ÿ“Š Poll
387
408
 
388
409
  ```javascript
@@ -827,7 +848,8 @@ sock.sendMessage(jid, {
827
848
  copy: '@itsliaaa/baileys'
828
849
  }, {
829
850
  text: '๐ŸŒ Source',
830
- url: 'https://www.npmjs.com/package/@itsliaaa/baileys'
851
+ url: 'https://www.npmjs.com/package/@itsliaaa/baileys',
852
+ useWebview: true // --- Optional
831
853
  }, {
832
854
  text: '๐Ÿ“‹ Select',
833
855
  sections: [{
@@ -867,7 +889,8 @@ sock.sendMessage(jid, {
867
889
  footer: '๐Ÿท๏ธ๏ธ Pinterest',
868
890
  nativeFlow: [{
869
891
  text: '๐ŸŒ Source',
870
- url: 'https://www.npmjs.com/package/@itsliaaa/baileys'
892
+ url: 'https://www.npmjs.com/package/@itsliaaa/baileys',
893
+ useWebview: true
871
894
  }]
872
895
  }, {
873
896
  image: {
@@ -897,7 +920,8 @@ sock.sendMessage(jid, {
897
920
  offerExpiration: Date.now() + 3_600_000,
898
921
  nativeFlow: [{
899
922
  text: '๐Ÿ›’ Product',
900
- id: '#Product'
923
+ id: '#Product',
924
+ icon: 'default'
901
925
  }, {
902
926
  text: '๐ŸŒ Source',
903
927
  url: 'https://www.npmjs.com/package/@itsliaaa/baileys'
@@ -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
  };
@@ -590,6 +559,7 @@ const prepareNativeFlowButtons = (message) => {
590
559
  display_text: buttonText || '๐ŸŒ Visit',
591
560
  url: button.url,
592
561
  merchant_url: button.url,
562
+ webview_interaction: button.useWebview,
593
563
  icon: buttonIcon
594
564
  })
595
565
  };
@@ -1318,6 +1288,12 @@ export const generateWAMessageContent = async (message, options) => {
1318
1288
  }
1319
1289
  m = { invoiceMessage };
1320
1290
  }
1291
+ if (shouldIncludeReportingToken(m)) {
1292
+ m.messageContextInfo = m.messageContextInfo || {};
1293
+ if (!m.messageContextInfo.messageSecret) {
1294
+ m.messageContextInfo.messageSecret = randomBytes(32);
1295
+ }
1296
+ }
1321
1297
  // Lia@Changes 31-01-26 --- Add direct externalAdReply access (no need to create contextInfo first)
1322
1298
  if (hasOptionalProperty(message, 'externalAdReply') && !!message.externalAdReply) {
1323
1299
  const messageType = Object.keys(m)[0];
@@ -1335,9 +1311,9 @@ export const generateWAMessageContent = async (message, options) => {
1335
1311
  mediaType: content.mediaType || 1,
1336
1312
  mediaUrl: content.url,
1337
1313
  renderLargerThumbnail: content.largeThumbnail,
1338
- sourceUrl: content.url + '?update=' + Date.now(),
1314
+ sourceUrl: content.url,
1339
1315
  thumbnail: content.thumbnail,
1340
- thumbnailUrl: content.url,
1316
+ thumbnailUrl: content.url + '?update=' + Date.now(),
1341
1317
  title: content.title || LIBRARY_NAME
1342
1318
  };
1343
1319
  delete externalAdReply.subTitle;
@@ -1433,12 +1409,6 @@ export const generateWAMessageContent = async (message, options) => {
1433
1409
  }
1434
1410
  }
1435
1411
  }
1436
- if (shouldIncludeReportingToken(m)) {
1437
- m.messageContextInfo = m.messageContextInfo || {};
1438
- if (!m.messageContextInfo.messageSecret) {
1439
- m.messageContextInfo.messageSecret = randomBytes(32);
1440
- }
1441
- }
1442
1412
  return proto.Message.create(m);
1443
1413
  };
1444
1414
  export const generateWAMessageFromContent = (jid, message, options) => {
@@ -5,6 +5,7 @@ import { initAuthCreds } from './auth-utils.js';
5
5
  import { BufferJSON } from './generics.js';
6
6
  // Lia@Changes 25-03-26 --- Add useSingleFileAuthState with integrated cache
7
7
  const FLUSH_TIMEOUT_MS = 3000;
8
+ // Lia@Note 21-04-26 --- Unstable need enhancement soon!
8
9
  export const useSingleFileAuthState = async (fileName) => {
9
10
  const cache = new Map();
10
11
  let isLoaded,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itsliaaa/baileys",
3
- "version": "0.1.28",
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",