@d0v3riz/baileys 6.7.4 → 6.7.5

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
@@ -324,13 +324,13 @@ const sock = makeWASocket({ })
324
324
  // the store can listen from a new socket once the current socket outlives its lifetime
325
325
  store.bind(sock.ev)
326
326
 
327
- sock.ev.on('chats.set', () => {
327
+ sock.ev.on('chats.upsert', () => {
328
328
  // can use "store.chats" however you want, even after the socket dies out
329
329
  // "chats" => a KeyedDB instance
330
330
  console.log('got chats', store.chats.all())
331
331
  })
332
332
 
333
- sock.ev.on('contacts.set', () => {
333
+ sock.ev.on('contacts.upsert', () => {
334
334
  console.log('got contacts', Object.values(store.contacts))
335
335
  })
336
336
 
@@ -422,7 +422,8 @@ await sock.sendMessage(
422
422
  {
423
423
  video: "./Media/ma_gif.mp4",
424
424
  caption: "hello!",
425
- gifPlayback: true
425
+ gifPlayback: true,
426
+ ptv: false // if set to true, will send as a `video note`
426
427
  }
427
428
  )
428
429
 
@@ -86,6 +86,7 @@ export declare const makeBusinessSocket: (config: SocketConfig) => {
86
86
  updateProfileStatus: (status: string) => Promise<void>;
87
87
  updateProfileName: (name: string) => Promise<void>;
88
88
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
89
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
89
90
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
90
91
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
91
92
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Boom } from '@hapi/boom';
3
3
  import { proto } from '../../WAProto';
4
- import { ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAPatchCreate, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types';
4
+ import { ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAPatchCreate, WAPresence, WAPrivacyCallValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types';
5
5
  import { BinaryNode } from '../WABinary';
6
6
  export declare const makeChatsSocket: (config: SocketConfig) => {
7
7
  processingMutex: {
@@ -29,6 +29,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
29
29
  updateProfileStatus: (status: string) => Promise<void>;
30
30
  updateProfileName: (name: string) => Promise<void>;
31
31
  updateBlockStatus: (jid: string, action: 'block' | 'unblock') => Promise<void>;
32
+ updateCallPrivacy: (value: WAPrivacyCallValue) => Promise<void>;
32
33
  updateLastSeenPrivacy: (value: WAPrivacyValue) => Promise<void>;
33
34
  updateOnlinePrivacy: (value: WAPrivacyOnlineValue) => Promise<void>;
34
35
  updateProfilePicturePrivacy: (value: WAPrivacyValue) => Promise<void>;
@@ -61,23 +62,20 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
61
62
  creds: import("../Types").AuthenticationCreds;
62
63
  keys: import("../Types").SignalKeyStoreWithTransaction;
63
64
  };
64
- /**
65
- * Star or Unstar a message
66
- */
67
65
  signalRepository: import("../Types").SignalRepository;
68
66
  user: import("../Types").Contact | undefined;
69
67
  generateMessageTag: () => string;
70
68
  query: (node: BinaryNode, timeoutMs?: number | undefined) => Promise<BinaryNode>;
71
69
  waitForMessage: <T_2>(msgId: string, timeoutMs?: number | undefined) => Promise<T_2>;
70
+ /**
71
+ * Star or Unstar a message
72
+ */
72
73
  waitForSocketOpen: () => Promise<void>;
73
74
  sendRawMessage: (data: Uint8Array | Buffer) => Promise<void>;
74
75
  sendNode: (frame: BinaryNode) => Promise<void>;
75
76
  logout: (msg?: string | undefined) => Promise<void>;
76
77
  end: (error: Error | undefined) => void;
77
78
  onUnexpectedError: (err: Error | Boom<any>, msg: string) => void;
78
- /**
79
- * Adds label for the chats
80
- */
81
79
  uploadPreKeys: (count?: number) => Promise<void>;
82
80
  uploadPreKeysToServerIfRequired: () => Promise<void>;
83
81
  requestPairingCode: (phoneNumber: string) => Promise<string>;
@@ -66,6 +66,9 @@ const makeChatsSocket = (config) => {
66
66
  }]
67
67
  });
68
68
  };
69
+ const updateCallPrivacy = async (value) => {
70
+ await privacyQuery('calladd', value);
71
+ };
69
72
  const updateLastSeenPrivacy = async (value) => {
70
73
  await privacyQuery('last', value);
71
74
  };
@@ -442,7 +445,8 @@ const makeChatsSocket = (config) => {
442
445
  const result = await query({
443
446
  tag: 'iq',
444
447
  attrs: {
445
- to: jid,
448
+ target: jid,
449
+ to: WABinary_1.S_WHATSAPP_NET,
446
450
  type: 'get',
447
451
  xmlns: 'w:profile:picture'
448
452
  },
@@ -817,6 +821,7 @@ const makeChatsSocket = (config) => {
817
821
  updateProfileStatus,
818
822
  updateProfileName,
819
823
  updateBlockStatus,
824
+ updateCallPrivacy,
820
825
  updateLastSeenPrivacy,
821
826
  updateOnlinePrivacy,
822
827
  updateProfilePicturePrivacy,
@@ -62,6 +62,7 @@ export declare const makeGroupsSocket: (config: SocketConfig) => {
62
62
  updateProfileStatus: (status: string) => Promise<void>;
63
63
  updateProfileName: (name: string) => Promise<void>;
64
64
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
65
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
65
66
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
66
67
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
67
68
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -193,6 +193,7 @@ const makeGroupsSocket = (config) => {
193
193
  * @param inviteMessage the message to accept
194
194
  */
195
195
  groupAcceptInviteV4: ev.createBufferedFunction(async (key, inviteMessage) => {
196
+ var _a;
196
197
  key = typeof key === 'string' ? { remoteJid: key } : key;
197
198
  const results = await groupQuery(inviteMessage.groupJid, 'set', [{
198
199
  tag: 'accept',
@@ -224,7 +225,7 @@ const makeGroupsSocket = (config) => {
224
225
  await upsertMessage({
225
226
  key: {
226
227
  remoteJid: inviteMessage.groupJid,
227
- id: (0, Utils_1.generateMessageID)(),
228
+ id: (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id),
228
229
  fromMe: false,
229
230
  participant: key.remoteJid,
230
231
  },
@@ -87,6 +87,7 @@ declare const makeWASocket: (config: UserFacingSocketConfig) => {
87
87
  updateProfileStatus: (status: string) => Promise<void>;
88
88
  updateProfileName: (name: string) => Promise<void>;
89
89
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
90
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
90
91
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
91
92
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
92
93
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -74,6 +74,7 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
74
74
  updateProfileStatus: (status: string) => Promise<void>;
75
75
  updateProfileName: (name: string) => Promise<void>;
76
76
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
77
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
77
78
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
78
79
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
79
80
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -75,15 +75,16 @@ const makeMessagesRecvSocket = (config) => {
75
75
  await query(stanza);
76
76
  };
77
77
  const sendRetryRequest = async (node, forceIncludeKeys = false) => {
78
- const msgId = node.attrs.id;
79
- let retryCount = msgRetryCache.get(msgId) || 0;
78
+ const { id: msgId, participant } = node.attrs;
79
+ const key = `${msgId}:${participant}`;
80
+ let retryCount = msgRetryCache.get(key) || 0;
80
81
  if (retryCount >= maxMsgRetryCount) {
81
82
  logger.debug({ retryCount, msgId }, 'reached retry limit, clearing');
82
- msgRetryCache.del(msgId);
83
+ msgRetryCache.del(key);
83
84
  return;
84
85
  }
85
86
  retryCount += 1;
86
- msgRetryCache.set(msgId, retryCount);
87
+ msgRetryCache.set(key, retryCount);
87
88
  const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds;
88
89
  const deviceIdentity = (0, Utils_1.encodeSignedDeviceIdentity)(account, true);
89
90
  await authState.keys.transaction(async () => {
@@ -190,6 +191,11 @@ const makeMessagesRecvSocket = (config) => {
190
191
  }
191
192
  };
192
193
  break;
194
+ case 'modify':
195
+ const oldNumber = (0, WABinary_1.getBinaryNodeChildren)(child, 'participant').map(p => p.attrs.jid);
196
+ msg.messageStubParameters = oldNumber || [];
197
+ msg.messageStubType = Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER;
198
+ break;
193
199
  case 'promote':
194
200
  case 'demote':
195
201
  case 'remove':
@@ -343,7 +349,7 @@ const makeMessagesRecvSocket = (config) => {
343
349
  const ref = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_ref'));
344
350
  const primaryIdentityPublicKey = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'primary_identity_pub'));
345
351
  const primaryEphemeralPublicKeyWrapped = toRequiredBuffer((0, WABinary_1.getBinaryNodeChildBuffer)(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub'));
346
- const codePairingPublicKey = decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
352
+ const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped);
347
353
  const companionSharedKey = Utils_1.Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
348
354
  const random = (0, crypto_1.randomBytes)(32);
349
355
  const linkCodeSalt = (0, crypto_1.randomBytes)(32);
@@ -400,10 +406,10 @@ const makeMessagesRecvSocket = (config) => {
400
406
  return result;
401
407
  }
402
408
  };
403
- function decipherLinkPublicKey(data) {
409
+ async function decipherLinkPublicKey(data) {
404
410
  const buffer = toRequiredBuffer(data);
405
411
  const salt = buffer.slice(0, 32);
406
- const secretKey = (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
412
+ const secretKey = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
407
413
  const iv = buffer.slice(32, 48);
408
414
  const payload = buffer.slice(48, 80);
409
415
  return (0, Utils_1.aesDecryptCTR)(payload, secretKey, iv);
@@ -69,6 +69,7 @@ export declare const makeMessagesSocket: (config: SocketConfig) => {
69
69
  updateProfileStatus: (status: string) => Promise<void>;
70
70
  updateProfileName: (name: string) => Promise<void>;
71
71
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
72
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
72
73
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
73
74
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
74
75
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -130,6 +130,9 @@ const makeMessagesSocket = (config) => {
130
130
  users.push({ tag: 'user', attrs: { jid } });
131
131
  }
132
132
  }
133
+ if (!users.length) {
134
+ return deviceResults;
135
+ }
133
136
  const iq = {
134
137
  tag: 'iq',
135
138
  attrs: {
@@ -247,6 +250,7 @@ const makeMessagesSocket = (config) => {
247
250
  return { nodes, shouldIncludeDeviceIdentity };
248
251
  };
249
252
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, cachedGroupMetadata, statusJidList }) => {
253
+ var _a;
250
254
  const meId = authState.creds.me.id;
251
255
  let shouldIncludeDeviceIdentity = false;
252
256
  const { user, server } = (0, WABinary_1.jidDecode)(jid);
@@ -254,7 +258,7 @@ const makeMessagesSocket = (config) => {
254
258
  const isGroup = server === 'g.us';
255
259
  const isStatus = jid === statusJid;
256
260
  const isLid = server === 'lid';
257
- msgId = msgId || (0, Utils_1.generateMessageID)();
261
+ msgId = msgId || (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id);
258
262
  useUserDevicesCache = useUserDevicesCache !== false;
259
263
  const participants = [];
260
264
  const destinationJid = (!isStatus) ? (0, WABinary_1.jidEncode)(user, isLid ? 'lid' : isGroup ? 'g.us' : 's.whatsapp.net') : statusJid;
@@ -601,7 +605,7 @@ const makeMessagesSocket = (config) => {
601
605
  return message;
602
606
  },
603
607
  sendMessage: async (jid, content, options = {}) => {
604
- var _a, _b;
608
+ var _a, _b, _c;
605
609
  const userJid = authState.creds.me.id;
606
610
  if (typeof content === 'object' &&
607
611
  'disappearingMessagesInChat' in content &&
@@ -631,6 +635,7 @@ const makeMessagesSocket = (config) => {
631
635
  upload: waUploadToServer,
632
636
  mediaCache: config.mediaCache,
633
637
  options: config.options,
638
+ messageId: (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id),
634
639
  ...options,
635
640
  });
636
641
  const isDeleteMsg = 'delete' in content && !!content.delete;
@@ -639,7 +644,7 @@ const makeMessagesSocket = (config) => {
639
644
  // required for delete
640
645
  if (isDeleteMsg) {
641
646
  // if the chat is a group, and I am not the author, then delete the message as an admin
642
- if ((0, WABinary_1.isJidGroup)((_a = content.delete) === null || _a === void 0 ? void 0 : _a.remoteJid) && !((_b = content.delete) === null || _b === void 0 ? void 0 : _b.fromMe)) {
647
+ if ((0, WABinary_1.isJidGroup)((_b = content.delete) === null || _b === void 0 ? void 0 : _b.remoteJid) && !((_c = content.delete) === null || _c === void 0 ? void 0 : _c.fromMe)) {
643
648
  additionalAttributes.edit = '8';
644
649
  }
645
650
  else {
@@ -88,6 +88,7 @@ export declare const makeRegistrationSocket: (config: SocketConfig) => {
88
88
  updateProfileStatus: (status: string) => Promise<void>;
89
89
  updateProfileName: (name: string) => Promise<void>;
90
90
  updateBlockStatus: (jid: string, action: "block" | "unblock") => Promise<void>;
91
+ updateCallPrivacy: (value: import("../Types").WAPrivacyCallValue) => Promise<void>;
91
92
  updateLastSeenPrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
92
93
  updateOnlinePrivacy: (value: import("../Types").WAPrivacyOnlineValue) => Promise<void>;
93
94
  updateProfilePicturePrivacy: (value: import("../Types").WAPrivacyValue) => Promise<void>;
@@ -403,7 +403,7 @@ const makeSocket = (config) => {
403
403
  {
404
404
  tag: 'companion_platform_id',
405
405
  attrs: {},
406
- content: '49' // Chrome
406
+ content: (0, Utils_1.getPlatformId)(browser[1])
407
407
  },
408
408
  {
409
409
  tag: 'companion_platform_display',
@@ -424,7 +424,7 @@ const makeSocket = (config) => {
424
424
  async function generatePairingKey() {
425
425
  const salt = (0, crypto_1.randomBytes)(32);
426
426
  const randomIv = (0, crypto_1.randomBytes)(16);
427
- const key = (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
427
+ const key = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
428
428
  const ciphered = (0, Utils_1.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
429
429
  return Buffer.concat([salt, randomIv, ciphered]);
430
430
  }
@@ -8,6 +8,7 @@ import type { MinimalMessage } from './Message';
8
8
  export type WAPrivacyValue = 'all' | 'contacts' | 'contact_blacklist' | 'none';
9
9
  export type WAPrivacyOnlineValue = 'all' | 'match_last_seen';
10
10
  export type WAReadReceiptsValue = 'all' | 'none';
11
+ export type WAPrivacyCallValue = 'all' | 'known';
11
12
  /** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */
12
13
  export type WAPresence = 'unavailable' | 'available' | 'composing' | 'recording' | 'paused';
13
14
  export declare const ALL_WA_PATCH_NAMES: readonly ["critical_block", "critical_unblock_low", "regular_high", "regular_low", "regular"];
@@ -4,7 +4,7 @@ export type GroupParticipant = (Contact & {
4
4
  isSuperAdmin?: boolean;
5
5
  admin?: 'admin' | 'superadmin' | null;
6
6
  });
7
- export type ParticipantAction = 'add' | 'remove' | 'promote' | 'demote';
7
+ export type ParticipantAction = 'add' | 'remove' | 'promote' | 'demote' | 'modify';
8
8
  export type RequestJoinAction = 'created' | 'revoked' | 'rejected';
9
9
  export type RequestJoinMethod = 'invite_link' | 'linked_group_join' | 'non_admin_add' | undefined;
10
10
  export interface GroupMetadata {
@@ -14,6 +14,13 @@ import { SocketConfig } from './Socket';
14
14
  export type UserFacingSocketConfig = Partial<SocketConfig> & {
15
15
  auth: AuthenticationState;
16
16
  };
17
+ export type BrowsersMap = {
18
+ ubuntu(browser: string): [string, string, string];
19
+ macOS(browser: string): [string, string, string];
20
+ baileys(browser: string): [string, string, string];
21
+ windows(browser: string): [string, string, string];
22
+ appropriate(browser: string): [string, string, string];
23
+ };
17
24
  export declare enum DisconnectReason {
18
25
  connectionClosed = 428,
19
26
  connectionLost = 408,
@@ -38,4 +38,4 @@ export declare function hkdf(buffer: Uint8Array | Buffer, expandedLength: number
38
38
  salt?: Buffer;
39
39
  info?: string;
40
40
  }): Buffer;
41
- export declare function derivePairingCodeKey(pairingCode: string, salt: Buffer): Buffer;
41
+ export declare function derivePairingCodeKey(pairingCode: string, salt: Buffer): Promise<Buffer>;
@@ -30,7 +30,9 @@ exports.derivePairingCodeKey = exports.hkdf = exports.md5 = exports.sha256 = exp
30
30
  const crypto_1 = require("crypto");
31
31
  const futoin_hkdf_1 = __importDefault(require("futoin-hkdf"));
32
32
  const libsignal = __importStar(require("libsignal"));
33
+ const util_1 = require("util");
33
34
  const Defaults_1 = require("../Defaults");
35
+ const pbkdf2Promise = (0, util_1.promisify)(crypto_1.pbkdf2);
34
36
  /** prefix version byte to the pub keys, required for some curve crypto functions */
35
37
  const generateSignalPubKey = (pubKey) => (pubKey.length === 33
36
38
  ? pubKey
@@ -145,7 +147,7 @@ function hkdf(buffer, expandedLength, info) {
145
147
  return (0, futoin_hkdf_1.default)(!Buffer.isBuffer(buffer) ? Buffer.from(buffer) : buffer, expandedLength, info);
146
148
  }
147
149
  exports.hkdf = hkdf;
148
- function derivePairingCodeKey(pairingCode, salt) {
149
- return (0, crypto_1.pbkdf2Sync)(pairingCode, salt, 2 << 16, 32, 'sha256');
150
+ async function derivePairingCodeKey(pairingCode, salt) {
151
+ return await pbkdf2Promise(pairingCode, salt, 2 << 16, 32, 'sha256');
150
152
  }
151
153
  exports.derivePairingCodeKey = derivePairingCodeKey;
@@ -2,16 +2,10 @@
2
2
  import { AxiosRequestConfig } from 'axios';
3
3
  import { Logger } from 'pino';
4
4
  import { proto } from '../../WAProto';
5
- import { BaileysEventEmitter, BaileysEventMap, WACallUpdateType, WAVersion } from '../Types';
5
+ import { BaileysEventEmitter, BaileysEventMap, BrowsersMap, WACallUpdateType, WAVersion } from '../Types';
6
6
  import { BinaryNode } from '../WABinary';
7
- export declare const Browsers: {
8
- ubuntu: (browser: any) => [string, string, string];
9
- macOS: (browser: any) => [string, string, string];
10
- baileys: (browser: any) => [string, string, string];
11
- windows: (browser: any) => [string, string, string];
12
- /** The appropriate browser based on your OS & release */
13
- appropriate: (browser: any) => [string, string, string];
14
- };
7
+ export declare const Browsers: BrowsersMap;
8
+ export declare const getPlatformId: (browser: string) => any;
15
9
  export declare const BufferJSON: {
16
10
  replacer: (k: any, value: any) => any;
17
11
  reviver: (_: any, value: any) => any;
@@ -38,6 +32,7 @@ export declare const delayCancellable: (ms: number) => {
38
32
  cancel: () => void;
39
33
  };
40
34
  export declare function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v: T) => void, reject: (error: any) => void) => void): Promise<T>;
35
+ export declare const generateMessageIDV2: (userId?: string) => string;
41
36
  export declare const generateMessageID: () => string;
42
37
  export declare function bindWaitForEvent<T extends keyof BaileysEventMap>(ev: BaileysEventEmitter, event: T): (check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => Promise<void>;
43
38
  export declare const bindWaitForConnectionUpdate: (ev: BaileysEventEmitter) => (check: (u: Partial<import("../Types").ConnectionState>) => boolean | undefined, timeoutMs?: number) => Promise<void>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.Browsers = void 0;
6
+ exports.bytesToCrockford = exports.trimUndefined = exports.isWABusinessPlatform = exports.getCodeFromWSError = exports.getCallStatusFromNode = exports.getErrorCodeFromStreamError = exports.getStatusFromReceiptType = exports.generateMdTagPrefix = exports.fetchLatestWaWebVersion = exports.fetchLatestBaileysVersion = exports.printQRIfNecessaryListener = exports.bindWaitForConnectionUpdate = exports.bindWaitForEvent = exports.generateMessageID = exports.generateMessageIDV2 = exports.promiseTimeout = exports.delayCancellable = exports.delay = exports.debouncedTimeout = exports.unixTimestampSeconds = exports.toNumber = exports.encodeBigEndian = exports.generateRegistrationId = exports.encodeWAMessage = exports.unpadRandomMax16 = exports.writeRandomPadMax16 = exports.getKeyAuthor = exports.BufferJSON = exports.getPlatformId = exports.Browsers = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const crypto_1 = require("crypto");
@@ -16,16 +16,24 @@ const PLATFORM_MAP = {
16
16
  'aix': 'AIX',
17
17
  'darwin': 'Mac OS',
18
18
  'win32': 'Windows',
19
- 'android': 'Android'
19
+ 'android': 'Android',
20
+ 'freebsd': 'FreeBSD',
21
+ 'openbsd': 'OpenBSD',
22
+ 'sunos': 'Solaris'
20
23
  };
21
24
  exports.Browsers = {
22
- ubuntu: browser => ['Ubuntu', browser, '20.0.04'],
23
- macOS: browser => ['Mac OS', browser, '10.15.7'],
24
- baileys: browser => ['Baileys', browser, '4.0.0'],
25
- windows: browser => ['Windows', browser, '10.0.22621'],
25
+ ubuntu: (browser) => ['Ubuntu', browser, '22.04.4'],
26
+ macOS: (browser) => ['Mac OS', browser, '14.4.1'],
27
+ baileys: (browser) => ['Baileys', browser, '6.5.0'],
28
+ windows: (browser) => ['Windows', browser, '10.0.22631'],
26
29
  /** The appropriate browser based on your OS & release */
27
- appropriate: browser => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
30
+ appropriate: (browser) => [PLATFORM_MAP[(0, os_1.platform)()] || 'Ubuntu', browser, (0, os_1.release)()]
28
31
  };
32
+ const getPlatformId = (browser) => {
33
+ const platformType = WAProto_1.proto.DeviceProps.PlatformType[browser.toUpperCase()];
34
+ return platformType ? platformType.toString().charCodeAt(0).toString() : '49'; //chrome
35
+ };
36
+ exports.getPlatformId = getPlatformId;
29
37
  exports.BufferJSON = {
30
38
  replacer: (k, value) => {
31
39
  if (Buffer.isBuffer(value) || value instanceof Uint8Array || (value === null || value === void 0 ? void 0 : value.type) === 'Buffer') {
@@ -147,8 +155,26 @@ async function promiseTimeout(ms, promise) {
147
155
  return p;
148
156
  }
149
157
  exports.promiseTimeout = promiseTimeout;
158
+ // inspired from whatsmeow code
159
+ // https://github.com/tulir/whatsmeow/blob/64bc969fbe78d31ae0dd443b8d4c80a5d026d07a/send.go#L42
160
+ const generateMessageIDV2 = (userId) => {
161
+ const data = Buffer.alloc(8 + 20 + 16);
162
+ data.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)));
163
+ if (userId) {
164
+ const id = (0, WABinary_1.jidDecode)(userId);
165
+ if (id === null || id === void 0 ? void 0 : id.user) {
166
+ data.write(id.user, 8);
167
+ data.write('@c.us', 8 + id.user.length);
168
+ }
169
+ }
170
+ const random = (0, crypto_1.randomBytes)(16);
171
+ random.copy(data, 28);
172
+ const hash = (0, crypto_1.createHash)('sha256').update(data).digest();
173
+ return (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + hash.toString('hex').toUpperCase().substring(0, 18);
174
+ };
175
+ exports.generateMessageIDV2 = generateMessageIDV2;
150
176
  // generate a random ID to attach to a message
151
- const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(6).toString('hex').toUpperCase();
177
+ const generateMessageID = () => (process.env.WHATSAPP_CONN_IDMSG || 'WHPI') + (0, crypto_1.randomBytes)(18).toString('hex').toUpperCase();
152
178
  exports.generateMessageID = generateMessageID;
153
179
  function bindWaitForEvent(ev, event) {
154
180
  return async (check, timeoutMs) => {
@@ -93,6 +93,7 @@ export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logg
93
93
  export declare const encryptMediaRetryRequest: (key: proto.IMessageKey, mediaKey: Buffer | Uint8Array, meId: string) => BinaryNode;
94
94
  export declare const decodeMediaRetryNode: (node: BinaryNode) => {
95
95
  key: proto.IMessageKey;
96
+ /** generates all the keys required to encrypt/decrypt & sign a media message */
96
97
  media?: {
97
98
  ciphertext: Uint8Array;
98
99
  iv: Uint8Array;
@@ -22,9 +22,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
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;
27
30
  const boom_1 = require("@hapi/boom");
31
+ const axios_1 = __importDefault(require("axios"));
28
32
  const child_process_1 = require("child_process");
29
33
  const Crypto = __importStar(require("crypto"));
30
34
  const events_1 = require("events");
@@ -313,8 +317,7 @@ async function generateThumbnail(file, mediaType, options) {
313
317
  }
314
318
  exports.generateThumbnail = generateThumbnail;
315
319
  const getHttpStream = async (url, options = {}) => {
316
- const { default: axios } = await import('axios');
317
- const fetched = await axios.get(url.toString(), { ...options, responseType: 'stream' });
320
+ const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
318
321
  return fetched.data;
319
322
  };
320
323
  exports.getHttpStream = getHttpStream;
@@ -525,27 +528,18 @@ exports.extensionForMediaMessage = extensionForMediaMessage;
525
528
  const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
526
529
  return async (stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
527
530
  var _a, _b;
528
- const { default: axios } = await import('axios');
529
531
  // send a query JSON to obtain the url & auth token to upload our media
530
532
  let uploadInfo = await refreshMediaConn(false);
531
533
  let urls;
532
534
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
533
- const chunks = [];
534
- for await (const chunk of stream) {
535
- chunks.push(chunk);
536
- }
537
- const reqBody = Buffer.concat(chunks);
538
535
  fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
539
- for (const { hostname, maxContentLengthBytes } of hosts) {
536
+ for (const { hostname } of hosts) {
540
537
  logger.debug(`uploading to "${hostname}"`);
541
538
  const auth = encodeURIComponent(uploadInfo.auth); // the auth token
542
539
  const url = `https://${hostname}${Defaults_1.MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
543
540
  let result;
544
541
  try {
545
- if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
546
- throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
547
- }
548
- const body = await axios.post(url, reqBody, {
542
+ const body = await axios_1.default.post(url, stream, {
549
543
  ...options,
550
544
  headers: {
551
545
  ...options.headers || {},
@@ -572,7 +566,7 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
572
566
  }
573
567
  }
574
568
  catch (error) {
575
- if (axios.isAxiosError(error)) {
569
+ if (axios_1.default.isAxiosError(error)) {
576
570
  result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
577
571
  }
578
572
  const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
@@ -326,6 +326,10 @@ const generateWAMessageContent = async (message, options) => {
326
326
  break;
327
327
  }
328
328
  }
329
+ else if ('ptv' in message && message.ptv) {
330
+ const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
331
+ m.ptvMessage = videoMessage;
332
+ }
329
333
  else if ('product' in message) {
330
334
  const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
331
335
  m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
@@ -17,5 +17,5 @@ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public
17
17
  finishInit: () => void;
18
18
  processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => Buffer;
19
19
  encodeFrame: (data: Buffer | Uint8Array) => Buffer;
20
- decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => void;
20
+ decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => Promise<void>;
21
21
  };
@@ -125,7 +125,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
125
125
  frame.set(data, introSize + 3);
126
126
  return frame;
127
127
  },
128
- decodeFrame: (newData, onFrame) => {
128
+ decodeFrame: async (newData, onFrame) => {
129
129
  var _a;
130
130
  // the binary protocol uses its own framing mechanism
131
131
  // on top of the WS frames
@@ -143,7 +143,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
143
143
  inBytes = inBytes.slice(size + 3);
144
144
  if (isFinished) {
145
145
  const result = decrypt(frame);
146
- frame = (0, WABinary_1.decodeBinaryNode)(result);
146
+ frame = await (0, WABinary_1.decodeBinaryNode)(result);
147
147
  }
148
148
  logger.trace({ msg: (_a = frame === null || frame === void 0 ? void 0 : frame.attrs) === null || _a === void 0 ? void 0 : _a.id }, 'recv frame');
149
149
  onFrame(frame);
@@ -225,6 +225,10 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
225
225
  };
226
226
  const participantsIncludesMe = () => participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid));
227
227
  switch (message.messageStubType) {
228
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
229
+ participants = message.messageStubParameters || [];
230
+ emitParticipantsUpdate('modify');
231
+ break;
228
232
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
229
233
  case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
230
234
  participants = message.messageStubParameters || [];
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getNextPreKeysNode = exports.getNextPreKeys = exports.extractDeviceJids = exports.parseAndInjectE2ESessions = exports.xmppPreKey = exports.xmppSignedPreKey = exports.generateOrGetPreKeys = exports.getPreKeys = exports.createSignalIdentity = void 0;
4
+ const lodash_1 = require("lodash");
4
5
  const Defaults_1 = require("../Defaults");
5
6
  const WABinary_1 = require("../WABinary");
6
7
  const crypto_1 = require("./crypto");
@@ -66,22 +67,31 @@ const parseAndInjectE2ESessions = async (node, repository) => {
66
67
  for (const node of nodes) {
67
68
  (0, WABinary_1.assertNodeErrorFree)(node);
68
69
  }
69
- await Promise.all(nodes.map(async (node) => {
70
- const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey');
71
- const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key');
72
- const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity');
73
- const jid = node.attrs.jid;
74
- const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4);
75
- await repository.injectE2ESession({
76
- jid,
77
- session: {
78
- registrationId: registrationId,
79
- identityKey: (0, crypto_1.generateSignalPubKey)(identity),
80
- signedPreKey: extractKey(signedKey),
81
- preKey: extractKey(key)
82
- }
83
- });
84
- }));
70
+ // Most of the work in repository.injectE2ESession is CPU intensive, not IO
71
+ // So Promise.all doesn't really help here,
72
+ // but blocks even loop if we're using it inside keys.transaction, and it makes it "sync" actually
73
+ // This way we chunk it in smaller parts and between those parts we can yield to the event loop
74
+ // It's rare case when you need to E2E sessions for so many users, but it's possible
75
+ const chunkSize = 100;
76
+ const chunks = (0, lodash_1.chunk)(nodes, chunkSize);
77
+ for (const nodesChunk of chunks) {
78
+ await Promise.all(nodesChunk.map(async (node) => {
79
+ const signedKey = (0, WABinary_1.getBinaryNodeChild)(node, 'skey');
80
+ const key = (0, WABinary_1.getBinaryNodeChild)(node, 'key');
81
+ const identity = (0, WABinary_1.getBinaryNodeChildBuffer)(node, 'identity');
82
+ const jid = node.attrs.jid;
83
+ const registrationId = (0, WABinary_1.getBinaryNodeChildUInt)(node, 'registration', 4);
84
+ await repository.injectE2ESession({
85
+ jid,
86
+ session: {
87
+ registrationId: registrationId,
88
+ identityKey: (0, crypto_1.generateSignalPubKey)(identity),
89
+ signedPreKey: extractKey(signedKey),
90
+ preKey: extractKey(key)
91
+ }
92
+ });
93
+ }));
94
+ }
85
95
  };
86
96
  exports.parseAndInjectE2ESessions = parseAndInjectE2ESessions;
87
97
  const extractDeviceJids = (result, myJid, excludeZeroDevices) => {
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import type { BinaryNode, BinaryNodeCodingOptions } from './types';
3
- export declare const decompressingIfRequired: (buffer: Buffer) => Buffer;
3
+ export declare const decompressingIfRequired: (buffer: Buffer) => Promise<Buffer>;
4
4
  export declare const decodeDecompressedBinaryNode: (buffer: Buffer, opts: Pick<BinaryNodeCodingOptions, 'DOUBLE_BYTE_TOKENS' | 'SINGLE_BYTE_TOKENS' | 'TAGS'>, indexRef?: {
5
5
  index: number;
6
6
  }) => BinaryNode;
7
- export declare const decodeBinaryNode: (buff: Buffer) => BinaryNode;
7
+ export declare const decodeBinaryNode: (buff: Buffer) => Promise<BinaryNode>;
@@ -24,12 +24,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.decodeBinaryNode = exports.decodeDecompressedBinaryNode = exports.decompressingIfRequired = void 0;
27
+ const util_1 = require("util");
27
28
  const zlib_1 = require("zlib");
28
29
  const constants = __importStar(require("./constants"));
29
30
  const jid_utils_1 = require("./jid-utils");
30
- const decompressingIfRequired = (buffer) => {
31
+ const inflatePromise = (0, util_1.promisify)(zlib_1.inflate);
32
+ const decompressingIfRequired = async (buffer) => {
31
33
  if (2 & buffer.readUInt8()) {
32
- buffer = (0, zlib_1.inflateSync)(buffer.slice(1));
34
+ buffer = await inflatePromise(buffer.slice(1));
33
35
  }
34
36
  else { // nodes with no compression have a 0x00 prefix, we remove that
35
37
  buffer = buffer.slice(1);
@@ -245,8 +247,8 @@ const decodeDecompressedBinaryNode = (buffer, opts, indexRef = { index: 0 }) =>
245
247
  };
246
248
  };
247
249
  exports.decodeDecompressedBinaryNode = decodeDecompressedBinaryNode;
248
- const decodeBinaryNode = (buff) => {
249
- const decompBuff = (0, exports.decompressingIfRequired)(buff);
250
+ const decodeBinaryNode = async (buff) => {
251
+ const decompBuff = await (0, exports.decompressingIfRequired)(buff);
250
252
  return (0, exports.decodeDecompressedBinaryNode)(decompBuff, constants);
251
253
  };
252
254
  exports.decodeBinaryNode = decodeBinaryNode;
@@ -1,3 +1,3 @@
1
1
  /// <reference types="node" />
2
2
  import type { BinaryNode, BinaryNodeCodingOptions } from './types';
3
- export declare const encodeBinaryNode: ({ tag, attrs, content }: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => Buffer;
3
+ export declare const encodeBinaryNode: (node: BinaryNode, opts?: Pick<BinaryNodeCodingOptions, 'TAGS' | 'TOKEN_MAP'>, buffer?: number[]) => Buffer;
@@ -26,7 +26,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.encodeBinaryNode = void 0;
27
27
  const constants = __importStar(require("./constants"));
28
28
  const jid_utils_1 = require("./jid-utils");
29
- const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0]) => {
29
+ const encodeBinaryNode = (node, opts = constants, buffer = [0]) => {
30
+ const encoded = encodeBinaryNodeInner(node, opts, buffer);
31
+ return Buffer.from(encoded);
32
+ };
33
+ exports.encodeBinaryNode = encodeBinaryNode;
34
+ const encodeBinaryNodeInner = ({ tag, attrs, content }, opts, buffer) => {
30
35
  const { TAGS, TOKEN_MAP } = opts;
31
36
  const pushByte = (value) => buffer.push(value & 0xff);
32
37
  const pushInt = (value, n, littleEndian = false) => {
@@ -214,7 +219,7 @@ const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0
214
219
  else if (Array.isArray(content)) {
215
220
  writeListStart(content.length);
216
221
  for (const item of content) {
217
- (0, exports.encodeBinaryNode)(item, opts, buffer);
222
+ encodeBinaryNodeInner(item, opts, buffer);
218
223
  }
219
224
  }
220
225
  else if (typeof content === 'undefined') {
@@ -223,6 +228,5 @@ const encodeBinaryNode = ({ tag, attrs, content }, opts = constants, buffer = [0
223
228
  else {
224
229
  throw new Error(`invalid children for header "${tag}": ${content} (${typeof content})`);
225
230
  }
226
- return Buffer.from(buffer);
231
+ return buffer;
227
232
  };
228
- exports.encodeBinaryNode = encodeBinaryNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d0v3riz/baileys",
3
- "version": "6.7.4",
3
+ "version": "6.7.5",
4
4
  "description": "WhatsApp API",
5
5
  "keywords": [
6
6
  "whatsapp",
@@ -48,16 +48,17 @@
48
48
  "@hapi/boom": "^9.1.3",
49
49
  "async-lock": "^1.4.1",
50
50
  "audio-decode": "^2.1.3",
51
- "axios": "^1.3.3",
51
+ "axios": "^1.6.0",
52
52
  "cache-manager": "4.0.1",
53
53
  "futoin-hkdf": "^1.5.1",
54
54
  "libphonenumber-js": "^1.10.20",
55
55
  "libsignal": "https://github.com/d0v3riz/libsignal-node.git",
56
+ "lodash": "^4.17.21",
56
57
  "music-metadata": "^7.12.3",
57
58
  "node-cache": "^5.1.2",
58
59
  "pino": "^7.0.0",
59
60
  "protobufjs": "^7.2.4",
60
- "uuid": "^9.0.0",
61
+ "uuid": "^10.0.0",
61
62
  "ws": "^8.13.0"
62
63
  },
63
64
  "devDependencies": {
@@ -76,7 +77,7 @@
76
77
  "open": "^8.4.2",
77
78
  "qrcode-terminal": "^0.12.0",
78
79
  "release-it": "^15.10.3",
79
- "sharp": "^0.30.5",
80
+ "sharp": "^0.32.6",
80
81
  "ts-jest": "^27.0.3",
81
82
  "ts-node": "^10.8.1",
82
83
  "typedoc": "^0.24.7",
@@ -86,7 +87,7 @@
86
87
  "jimp": "^0.16.1",
87
88
  "link-preview-js": "^3.0.0",
88
89
  "qrcode-terminal": "^0.12.0",
89
- "sharp": "^0.32.2"
90
+ "sharp": "^0.32.6"
90
91
  },
91
92
  "peerDependenciesMeta": {
92
93
  "jimp": {