@alannxd/baileys 2.1.4 → 3.0.3

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.
@@ -1,32 +1,38 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryIds = exports.XWAPaths = exports.MexOperations = void 0;
4
- var MexOperations;
5
- (function (MexOperations) {
6
- MexOperations["PROMOTE"] = "NotificationNewsletterAdminPromote";
7
- MexOperations["DEMOTE"] = "NotificationNewsletterAdminDemote";
8
- MexOperations["UPDATE"] = "NotificationNewsletterUpdate";
9
- })(MexOperations = exports.MexOperations || (exports.MexOperations = {}));
10
- var XWAPaths;
11
- (function (XWAPaths) {
12
- XWAPaths["PROMOTE"] = "xwa2_notify_newsletter_admin_promote";
13
- XWAPaths["DEMOTE"] = "xwa2_notify_newsletter_admin_demote";
14
- XWAPaths["ADMIN_COUNT"] = "xwa2_newsletter_admin";
15
- XWAPaths["CREATE"] = "xwa2_newsletter_create";
16
- XWAPaths["NEWSLETTER"] = "xwa2_newsletter";
17
- XWAPaths["METADATA_UPDATE"] = "xwa2_notify_newsletter_on_metadata_update";
18
- })(XWAPaths = exports.XWAPaths || (exports.XWAPaths = {}));
19
- var QueryIds;
20
- (function (QueryIds) {
21
- QueryIds["JOB_MUTATION"] = "7150902998257522";
22
- QueryIds["METADATA"] = "6620195908089573";
23
- QueryIds["UNFOLLOW"] = "7238632346214362";
24
- QueryIds["FOLLOW"] = "7871414976211147";
25
- QueryIds["UNMUTE"] = "7337137176362961";
26
- QueryIds["MUTE"] = "25151904754424642";
27
- QueryIds["CREATE"] = "6996806640408138";
28
- QueryIds["ADMIN_COUNT"] = "7130823597031706";
29
- QueryIds["CHANGE_OWNER"] = "7341777602580933";
30
- QueryIds["DELETE"] = "8316537688363079";
31
- QueryIds["DEMOTE"] = "6551828931592903";
32
- })(QueryIds = exports.QueryIds || (exports.QueryIds = {}));
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const MexOperations = {
6
+ PROMOTE: "NotificationNewsletterAdminPromote",
7
+ DEMOTE: "NotificationNewsletterAdminDemote",
8
+ UPDATE: "NotificationNewsletterUpdate"
9
+ }
10
+
11
+ const XWAPaths = {
12
+ PROMOTE: "xwa2_notify_newsletter_admin_promote",
13
+ DEMOTE: "xwa2_notify_newsletter_admin_demote",
14
+ ADMIN_COUNT: "xwa2_newsletter_admin",
15
+ CREATE: "xwa2_newsletter_create",
16
+ NEWSLETTER: "xwa2_newsletter",
17
+ SUBSCRIBED: "xwa2_newsletter_subscribed",
18
+ METADATA_UPDATE: "xwa2_notify_newsletter_on_metadata_update"
19
+ }
20
+
21
+ const QueryIds = {
22
+ JOB_MUTATION: "7150902998257522",
23
+ METADATA: "6620195908089573",
24
+ UNFOLLOW: "7238632346214362",
25
+ FOLLOW: "7871414976211147",
26
+ UNMUTE: "7337137176362961",
27
+ MUTE: "25151904754424642",
28
+ CREATE: "6996806640408138",
29
+ ADMIN_COUNT: "7130823597031706",
30
+ CHANGE_OWNER: "7341777602580933",
31
+ DELETE: "8316537688363079",
32
+ DEMOTE: "6551828931592903",
33
+ SUBSCRIBED: "6388546374527196"
34
+ }
35
+
36
+ exports.MexOperations = MexOperations
37
+ exports.XWAPaths = XWAPaths
38
+ exports.QueryIds = QueryIds
@@ -21,14 +21,16 @@ const PLATFORM_MAP = {
21
21
  'android': 'Android',
22
22
  'freebsd': 'FreeBSD',
23
23
  'openbsd': 'OpenBSD',
24
- 'sunos': 'Solaris'
24
+ 'sunos': 'Solaris',
25
+ 'linux': undefined,
26
+ 'haiku': undefined,
27
+ 'cygwin': undefined,
28
+ 'netbsd': undefined
25
29
  };
26
- exports.Browsers = {
27
- ubuntu: (browser) => ['Ubuntu', browser, '22.04.4'],
28
- macOS: (browser) => ['Mac OS', browser, '14.4.1'],
29
- baileys: (browser) => ['Baileys', browser, '6.5.0'],
30
- windows: (browser) => ['Windows', browser, '10.0.22631'],
31
- appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
30
+ exports.Browsers = (browser) => {
31
+ const osName = PLATFORM_MAP[os_1.platform()] || 'Ubuntu';
32
+ const osRelease = os_1.release();
33
+ return [osName, browser, osRelease];
32
34
  };
33
35
 
34
36
  const getPlatformId = (browser) => {
@@ -174,7 +176,7 @@ const generateMessageIDV2 = (userId) => {
174
176
  };
175
177
  exports.generateMessageIDV2 = generateMessageIDV2;
176
178
  // generate a random ID to attach to a message
177
- const generateMessageID = () => 'ST-' + (0, crypto_1.randomBytes)(6).toString('hex').toUpperCase();
179
+ const generateMessageID = () => 'ILSYM-' + (0, crypto_1.randomBytes)(6).toString('hex').toUpperCase();
178
180
  exports.generateMessageID = generateMessageID;
179
181
  function bindWaitForEvent(ev, event) {
180
182
  return async (check, timeoutMs) => {
@@ -188,68 +188,138 @@ const mediaMessageSHA256B64 = (message) => {
188
188
  };
189
189
  exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
190
190
  async function getAudioDuration(buffer) {
191
- const musicMetadata = await import('music-metadata');
192
- let metadata;
193
- if (Buffer.isBuffer(buffer)) {
194
- metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true });
195
- }
196
- else if (typeof buffer === 'string') {
197
- const rStream = (0, fs_1.createReadStream)(buffer);
198
- try {
199
- metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true });
200
- }
201
- finally {
202
- rStream.destroy();
191
+ try {
192
+ const { PassThrough } = require('stream');
193
+ const ff = require('fluent-ffmpeg');
194
+
195
+ return await new Promise((resolve, reject) => {
196
+ const inputStream = new PassThrough();
197
+ inputStream.end(buffer);
198
+
199
+ ff(inputStream)
200
+ .ffprobe((err, data) => {
201
+ if (err) reject(err);
202
+ else resolve(data.format.duration);
203
+ });
204
+ });
205
+ } catch (error) {
206
+ const musicMetadata = await import('music-metadata');
207
+ let metadata;
208
+ if (Buffer.isBuffer(buffer)) {
209
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, {
210
+ duration: true
211
+ });
212
+ } else if (typeof buffer === 'string') {
213
+ const rStream = (0, fs_1.createReadStream)(buffer);
214
+ try {
215
+ metadata = await musicMetadata.parseStream(rStream, undefined, {
216
+ duration: true
217
+ });
218
+ } finally {
219
+ rStream.destroy();
220
+ }
221
+ } else {
222
+ metadata = await musicMetadata.parseStream(buffer, undefined, {
223
+ duration: true
224
+ });
203
225
  }
226
+ return metadata.format.duration;
204
227
  }
205
- else {
206
- metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true });
207
- }
208
- return metadata.format.duration;
209
228
  }
210
229
  exports.getAudioDuration = getAudioDuration;
211
- /**
212
- referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
213
- */
214
230
  async function getAudioWaveform(buffer, logger) {
215
231
  try {
216
- const audioDecode = (buffer) => import('audio-decode').then(({ default: audioDecode }) => audioDecode(buffer));
232
+ const { PassThrough } = require('stream');
233
+ const ff = require('fluent-ffmpeg');
234
+
217
235
  let audioData;
218
236
  if (Buffer.isBuffer(buffer)) {
219
237
  audioData = buffer;
238
+ } else if (typeof buffer === 'string') {
239
+ const rStream = require('fs').createReadStream(buffer);
240
+ audioData = await exports.toBuffer(rStream);
241
+ } else {
242
+ audioData = await exports.toBuffer(buffer);
220
243
  }
221
- else if (typeof buffer === 'string') {
222
- const rStream = (0, fs_1.createReadStream)(buffer);
223
- audioData = await (0, exports.toBuffer)(rStream);
224
- }
225
- else {
226
- audioData = await (0, exports.toBuffer)(buffer);
227
- }
228
- const audioBuffer = await audioDecode(audioData);
229
- const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
230
- const samples = 64; // Number of samples we want to have in our final data set
231
- const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
232
- const filteredData = [];
233
- for (let i = 0; i < samples; i++) {
234
- const blockStart = blockSize * i; // the location of the first sample in the block
235
- let sum = 0;
236
- for (let j = 0; j < blockSize; j++) {
237
- sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
238
- }
239
- filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
240
- }
241
- // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
242
- const multiplier = Math.pow(Math.max(...filteredData), -1);
243
- const normalizedData = filteredData.map((n) => n * multiplier);
244
- // Generate waveform like WhatsApp
245
- const waveform = new Uint8Array(normalizedData.map((n) => Math.floor(100 * n)));
246
- return waveform;
247
- }
248
- catch (e) {
249
- logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
244
+
245
+ return await new Promise((resolve, reject) => {
246
+ const inputStream = new PassThrough();
247
+ inputStream.end(audioData);
248
+ const chunks = [];
249
+ const bars = 64;
250
+
251
+ ff(inputStream)
252
+ .audioChannels(1)
253
+ .audioFrequency(16000)
254
+ .format('s16le')
255
+ .on('error', reject)
256
+ .on('end', () => {
257
+ const rawData = Buffer.concat(chunks);
258
+ const samples = rawData.length / 2;
259
+ const amplitudes = [];
260
+
261
+ for (let i = 0; i < samples; i++) {
262
+ amplitudes.push(Math.abs(rawData.readInt16LE(i * 2)) / 32768);
263
+ }
264
+
265
+ const blockSize = Math.floor(amplitudes.length / bars);
266
+ const avg = [];
267
+ for (let i = 0; i < bars; i++) {
268
+ const block = amplitudes.slice(i * blockSize, (i + 1) * blockSize);
269
+ avg.push(block.reduce((a, b) => a + b, 0) / block.length);
270
+ }
271
+
272
+ const max = Math.max(...avg);
273
+ const normalized = avg.map(v => Math.floor((v / max) * 100));
274
+ resolve(new Uint8Array(normalized));
275
+ })
276
+ .pipe()
277
+ .on('data', chunk => chunks.push(chunk));
278
+ });
279
+ } catch (e) {
280
+ logger?.debug(e);
250
281
  }
251
282
  }
252
283
  exports.getAudioWaveform = getAudioWaveform;
284
+ async function convertToOpusBuffer(buffer, logger) {
285
+ try {
286
+ const { PassThrough } = require('stream');
287
+ const ff = require('fluent-ffmpeg');
288
+
289
+ return await new Promise((resolve, reject) => {
290
+ const inStream = new PassThrough();
291
+ const outStream = new PassThrough();
292
+ const chunks = [];
293
+ inStream.end(buffer);
294
+
295
+ ff(inStream)
296
+ .noVideo()
297
+ .audioCodec('libopus')
298
+ .format('ogg')
299
+ .audioBitrate('48k')
300
+ .audioChannels(1)
301
+ .audioFrequency(48000)
302
+ .outputOptions([
303
+ '-vn',
304
+ '-b:a 64k',
305
+ '-ac 2',
306
+ '-ar 48000',
307
+ '-map_metadata', '-1',
308
+ '-application', 'voip'
309
+ ])
310
+ .on('error', reject)
311
+ .on('end', () => resolve(Buffer.concat(chunks)))
312
+ .pipe(outStream, {
313
+ end: true
314
+ });
315
+ outStream.on('data', c => chunks.push(c));
316
+ });
317
+ } catch (e) {
318
+ logger?.debug(e);
319
+ throw e;
320
+ }
321
+ }
322
+ exports.convertToOpusBuffer = convertToOpusBuffer;
253
323
  const toReadable = (buffer) => {
254
324
  const readable = new stream_1.Readable({ read: () => { } });
255
325
  readable.push(buffer);
@@ -362,15 +432,28 @@ const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequi
362
432
  }
363
433
  };
364
434
  exports.prepareStream = prepareStream;
365
- const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
435
+ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus } = {}) => {
366
436
  const { stream, type } = await (0, exports.getStream)(media, opts);
367
- logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
437
+
438
+ let finalStream = stream;
439
+ if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
440
+ try {
441
+ const buffer = await (0, exports.toBuffer)(stream);
442
+ const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
443
+ finalStream = (0, exports.toReadable)(opusBuffer);
444
+ } catch (error) {
445
+ const { stream: newStream } = await (0, exports.getStream)(media, opts);
446
+ finalStream = newStream;
447
+ }
448
+ }
449
+
368
450
  const mediaKey = Crypto.randomBytes(32);
369
451
  const { cipherKey, iv, macKey } = getMediaKeys(mediaKey, mediaType);
370
452
  const encWriteStream = new stream_1.Readable({ read: () => { } });
371
453
  let bodyPath;
372
454
  let writeStream;
373
455
  let didSaveToTmpPath = false;
456
+
374
457
  if (type === 'file') {
375
458
  bodyPath = media.url;
376
459
  }
@@ -379,13 +462,15 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
379
462
  writeStream = (0, fs_1.createWriteStream)(bodyPath);
380
463
  didSaveToTmpPath = true;
381
464
  }
465
+
382
466
  let fileLength = 0;
383
467
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
384
468
  let hmac = Crypto.createHmac('sha256', macKey).update(iv);
385
469
  let sha256Plain = Crypto.createHash('sha256');
386
470
  let sha256Enc = Crypto.createHash('sha256');
471
+
387
472
  try {
388
- for await (const data of stream) {
473
+ for await (const data of finalStream) {
389
474
  fileLength += data.length;
390
475
  if (type === 'remote'
391
476
  && (opts === null || opts === void 0 ? void 0 : opts.maxContentLength)
@@ -394,6 +479,7 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
394
479
  data: { media, type }
395
480
  });
396
481
  }
482
+
397
483
  sha256Plain = sha256Plain.update(data);
398
484
  if (writeStream) {
399
485
  if (!writeStream.write(data)) {
@@ -402,16 +488,18 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
402
488
  }
403
489
  onChunk(aes.update(data));
404
490
  }
491
+
405
492
  onChunk(aes.final());
406
493
  const mac = hmac.digest().slice(0, 10);
407
494
  sha256Enc = sha256Enc.update(mac);
408
495
  const fileSha256 = sha256Plain.digest();
409
496
  const fileEncSha256 = sha256Enc.digest();
497
+
410
498
  encWriteStream.push(mac);
411
499
  encWriteStream.push(null);
412
500
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.end();
413
- stream.destroy();
414
- logger === null || logger === void 0 ? void 0 : logger.debug('encrypted data successfully');
501
+ finalStream.destroy();
502
+
415
503
  return {
416
504
  mediaKey,
417
505
  encWriteStream,
@@ -424,24 +512,24 @@ const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfReq
424
512
  };
425
513
  }
426
514
  catch (error) {
427
- // destroy all streams with error
428
515
  encWriteStream.destroy();
429
516
  writeStream === null || writeStream === void 0 ? void 0 : writeStream.destroy();
430
517
  aes.destroy();
431
518
  hmac.destroy();
432
519
  sha256Plain.destroy();
433
520
  sha256Enc.destroy();
434
- stream.destroy();
521
+ finalStream.destroy();
522
+
435
523
  if (didSaveToTmpPath) {
436
524
  try {
437
525
  await fs_1.promises.unlink(bodyPath);
438
526
  }
439
527
  catch (err) {
440
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
441
528
  }
442
529
  }
443
530
  throw error;
444
531
  }
532
+
445
533
  function onChunk(buff) {
446
534
  sha256Enc = sha256Enc.update(buff);
447
535
  hmac = hmac.update(buff);
@@ -74,59 +74,30 @@ const prepareWAMessageMedia = async (message, options) => {
74
74
  }
75
75
  }
76
76
  if (!mediaType) {
77
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
77
+ throw new boom_1.Boom('Invalid media type', {
78
+ statusCode: 400
79
+ });
78
80
  }
81
+
79
82
  const uploadData = {
80
83
  ...message,
81
- ...(message.annotations ? {
82
- annotations: message.annotations
83
- } : {
84
- annotations: [
85
- {
86
- polygonVertices: [
87
- {
88
- x: 60.71664810180664,
89
- y: -36.39784622192383
90
- },
91
- {
92
- x: -16.710189819335938,
93
- y: 49.263675689697266
94
- },
95
- {
96
- x: -56.585853576660156,
97
- y: 37.85963439941406
98
- },
99
- {
100
- x: 20.840980529785156,
101
- y: -47.80188751220703
102
- }
103
- ],
104
- newsletter: {
105
- newsletterJid: "120363297591152843@newsletter",
106
- serverMessageId: 0,
107
- newsletterName: "-",
108
- contentType: "UPDATE",
109
- }
110
- }
111
- ]
112
- }),
113
84
  media: message[mediaType]
114
85
  };
115
86
  delete uploadData[mediaType];
116
- // check if cacheable + generate cache key
117
87
  const cacheableKey = typeof uploadData.media === 'object' &&
118
88
  ('url' in uploadData.media) &&
119
89
  !!uploadData.media.url &&
120
90
  !!options.mediaCache && (
121
- // generate the key
122
91
  mediaType + ':' + uploadData.media.url.toString());
92
+
123
93
  if (mediaType === 'document' && !uploadData.fileName) {
124
94
  uploadData.fileName = 'file';
125
95
  }
96
+
126
97
  if (!uploadData.mimetype) {
127
98
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
128
99
  }
129
- // check for cache hit
100
+
130
101
  if (cacheableKey) {
131
102
  const mediaBuff = options.mediaCache.get(cacheableKey);
132
103
  if (mediaBuff) {
@@ -137,19 +108,28 @@ const prepareWAMessageMedia = async (message, options) => {
137
108
  return obj;
138
109
  }
139
110
  }
111
+
140
112
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
141
113
  const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
142
114
  (typeof uploadData['jpegThumbnail'] === 'undefined');
143
115
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
144
116
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
145
117
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
146
- const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
118
+
119
+ const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath, opusConverted } = await (options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
147
120
  logger,
148
121
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
149
- opts: options.options
122
+ opts: options.options,
123
+ isPtt: uploadData.ptt,
124
+ forceOpus: (mediaType === "audio" && uploadData.mimetype && uploadData.mimetype.includes('opus'))
150
125
  });
151
- // url safe Base64 encode the SHA256 hash of the body
126
+
127
+ if (mediaType === 'audio' && opusConverted) {
128
+ uploadData.mimetype = 'audio/ogg; codecs=opus';
129
+ }
130
+
152
131
  const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 !== null && fileEncSha256 !== void 0 ? fileEncSha256 : fileSha256).toString('base64');
132
+
153
133
  const [{ mediaUrl, directPath, handle }] = await Promise.all([
154
134
  (async () => {
155
135
  const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
@@ -176,10 +156,6 @@ const prepareWAMessageMedia = async (message, options) => {
176
156
  uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
177
157
  logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
178
158
  }
179
- if (requiresWaveformProcessing) {
180
- uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(bodyPath, logger);
181
- logger === null || logger === void 0 ? void 0 : logger.debug('processed waveform');
182
- }
183
159
  if (requiresAudioBackground) {
184
160
  uploadData.backgroundArgb = await assertColor(options.backgroundColor);
185
161
  logger === null || logger === void 0 ? void 0 : logger.debug('computed backgroundColor audio status');
@@ -194,12 +170,13 @@ const prepareWAMessageMedia = async (message, options) => {
194
170
  if (!Buffer.isBuffer(encWriteStream)) {
195
171
  encWriteStream.destroy();
196
172
  }
197
- // remove tmp files
173
+
198
174
  if (didSaveToTmpPath && bodyPath) {
199
175
  await fs_1.promises.unlink(bodyPath);
200
176
  logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
201
177
  }
202
178
  });
179
+
203
180
  const obj = Types_1.WAProto.Message.fromObject({
204
181
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
205
182
  url: handle ? undefined : mediaUrl,
@@ -213,14 +190,17 @@ const prepareWAMessageMedia = async (message, options) => {
213
190
  media: undefined
214
191
  })
215
192
  });
193
+
216
194
  if (uploadData.ptv) {
217
195
  obj.ptvMessage = obj.videoMessage;
218
196
  delete obj.videoMessage;
219
197
  }
198
+
220
199
  if (cacheableKey) {
221
200
  logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
222
201
  options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
223
202
  }
203
+
224
204
  return obj;
225
205
  };
226
206
  exports.prepareWAMessageMedia = prepareWAMessageMedia;
@@ -1,11 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMultiFileAuthState = void 0;
4
+ const async_mutex_1 = require("async-mutex");
4
5
  const promises_1 = require("fs/promises");
5
6
  const path_1 = require("path");
6
7
  const WAProto_1 = require("../../WAProto");
7
8
  const auth_utils_1 = require("./auth-utils");
8
9
  const generics_1 = require("./generics");
10
+ const fileLocks = new Map();
11
+ const getFileLock = (path) => {
12
+ let mutex = fileLocks.get(path);
13
+ if (!mutex) {
14
+ mutex = new async_mutex_1.Mutex();
15
+ fileLocks.set(path, mutex);
16
+ }
17
+ return mutex;
18
+ };
9
19
  /**
10
20
  * stores the full authentication state in a single folder.
11
21
  * Far more efficient than singlefileauthstate
@@ -14,13 +24,31 @@ const generics_1 = require("./generics");
14
24
  * Would recommend writing an auth state for use with a proper SQL or No-SQL DB
15
25
  * */
16
26
  const useMultiFileAuthState = async (folder) => {
17
- const writeData = (data, file) => {
18
- return (0, promises_1.writeFile)((0, path_1.join)(folder, fixFileName(file)), JSON.stringify(data, generics_1.BufferJSON.replacer));
27
+ const writeData = async (data, file) => {
28
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
29
+ const mutex = getFileLock(filePath);
30
+ return mutex.acquire().then(async (release) => {
31
+ try {
32
+ await (0, promises_1.writeFile)(filePath, JSON.stringify(data, generics_1.BufferJSON.replacer));
33
+ }
34
+ finally {
35
+ release();
36
+ }
37
+ });
19
38
  };
20
39
  const readData = async (file) => {
21
40
  try {
22
- const data = await (0, promises_1.readFile)((0, path_1.join)(folder, fixFileName(file)), { encoding: 'utf-8' });
23
- return JSON.parse(data, generics_1.BufferJSON.reviver);
41
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
42
+ const mutex = getFileLock(filePath);
43
+ return await mutex.acquire().then(async (release) => {
44
+ try {
45
+ const data = await (0, promises_1.readFile)(filePath, { encoding: 'utf-8' });
46
+ return JSON.parse(data, generics_1.BufferJSON.reviver);
47
+ }
48
+ finally {
49
+ release();
50
+ }
51
+ });
24
52
  }
25
53
  catch (error) {
26
54
  return null;
@@ -28,7 +56,18 @@ const useMultiFileAuthState = async (folder) => {
28
56
  };
29
57
  const removeData = async (file) => {
30
58
  try {
31
- await (0, promises_1.unlink)((0, path_1.join)(folder, fixFileName(file)));
59
+ const filePath = (0, path_1.join)(folder, fixFileName(file));
60
+ const mutex = getFileLock(filePath);
61
+ return mutex.acquire().then(async (release) => {
62
+ try {
63
+ await (0, promises_1.unlink)(filePath);
64
+ }
65
+ catch (_a) {
66
+ }
67
+ finally {
68
+ release();
69
+ }
70
+ });
32
71
  }
33
72
  catch (_a) {
34
73
  }
@@ -72,7 +111,7 @@ const useMultiFileAuthState = async (folder) => {
72
111
  }
73
112
  }
74
113
  },
75
- saveCreds: () => {
114
+ saveCreds: async () => {
76
115
  return writeData(creds, 'creds.json');
77
116
  }
78
117
  };