@nexustechpro/baileys 1.1.2 → 1.1.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.
- package/lib/Defaults/index.js +1 -0
- package/lib/Socket/messages-send.js +9 -56
- package/lib/Socket/nexus-handler.js +29 -7
- package/lib/Store/index.js +5 -5
- package/lib/Store/make-in-memory-store.js +2 -2
- package/lib/Utils/generics.js +34 -1
- package/lib/Utils/messages.js +8 -2
- package/lib/WABinary/generic-utils.js +94 -0
- package/lib/index.js +1 -1
- package/package.json +2 -1
package/lib/Defaults/index.js
CHANGED
|
@@ -23,7 +23,7 @@ const {
|
|
|
23
23
|
const {
|
|
24
24
|
areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser,
|
|
25
25
|
isJidGroup, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET,
|
|
26
|
-
getBinaryFilteredButtons, STORIES_JID, isJidUser, isJidNewsletter
|
|
26
|
+
getBinaryFilteredButtons, STORIES_JID, isJidUser, isJidNewsletter, getButtonArgs, getButtonType
|
|
27
27
|
} = WABinary
|
|
28
28
|
|
|
29
29
|
export const makeMessagesSocket = (config) => {
|
|
@@ -366,61 +366,6 @@ export const makeMessagesSocket = (config) => {
|
|
|
366
366
|
if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) return 'url'
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
const getButtonType = (message) => {
|
|
370
|
-
if (message.listMessage) return 'list'
|
|
371
|
-
if (message.buttonsMessage) return 'buttons'
|
|
372
|
-
const btn = message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name
|
|
373
|
-
if (['review_and_pay', 'review_order', 'payment_info', 'payment_status', 'payment_method'].includes(btn)) return btn
|
|
374
|
-
if (message.interactiveMessage?.nativeFlowMessage) return 'interactive'
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const getButtonArgs = (message) => {
|
|
378
|
-
const msgContent = message.viewOnceMessage?.message || message
|
|
379
|
-
const flowMsg = msgContent.interactiveMessage?.nativeFlowMessage
|
|
380
|
-
const btnFirst = flowMsg?.buttons?.[0]?.name
|
|
381
|
-
const specialBtns = ['mpm', 'cta_catalog', 'send_location', 'call_permission_request', 'wa_payment_transaction_details', 'automated_greeting_message_view_catalog']
|
|
382
|
-
|
|
383
|
-
const base = {
|
|
384
|
-
tag: 'biz',
|
|
385
|
-
attrs: { actual_actors: '2', host_storage: '2', privacy_mode_ts: unixTimestampSeconds().toString() }
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (flowMsg && (btnFirst === 'review_and_pay' || btnFirst === 'payment_info')) {
|
|
389
|
-
return { tag: 'biz', attrs: { native_flow_name: btnFirst === 'review_and_pay' ? 'order_details' : btnFirst } }
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (flowMsg && specialBtns.includes(btnFirst)) {
|
|
393
|
-
return {
|
|
394
|
-
...base,
|
|
395
|
-
content: [
|
|
396
|
-
{ tag: 'interactive', attrs: { type: 'native_flow', v: '1' }, content: [{ tag: 'native_flow', attrs: { v: '2', name: btnFirst } }] },
|
|
397
|
-
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
398
|
-
]
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (flowMsg || msgContent.buttonsMessage) {
|
|
403
|
-
return {
|
|
404
|
-
...base,
|
|
405
|
-
content: [
|
|
406
|
-
{ tag: 'interactive', attrs: { type: 'native_flow', v: '1' }, content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }] },
|
|
407
|
-
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
408
|
-
]
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (msgContent.listMessage) {
|
|
413
|
-
return {
|
|
414
|
-
...base,
|
|
415
|
-
content: [
|
|
416
|
-
{ tag: 'list', attrs: { v: '2', type: 'product_list' } },
|
|
417
|
-
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
418
|
-
]
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
return base
|
|
423
|
-
}
|
|
424
369
|
|
|
425
370
|
// ===== CORE MESSAGE RELAY =====
|
|
426
371
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList } = {}) => {
|
|
@@ -905,6 +850,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
905
850
|
const userJid = authState.creds.me.id
|
|
906
851
|
const { quoted } = options
|
|
907
852
|
|
|
853
|
+
// Handle interactive messages sent with 'interactive' key
|
|
854
|
+
// Convert to 'interactiveMessage' for nexus detection
|
|
855
|
+
if (content.interactive && !content.interactiveMessage) {
|
|
856
|
+
// Merge other content with interactiveMessage
|
|
857
|
+
const { interactive, ...otherContent } = content
|
|
858
|
+
content = { ...otherContent, interactiveMessage: interactive }
|
|
859
|
+
}
|
|
860
|
+
|
|
908
861
|
// Check if nexus can handle this message type
|
|
909
862
|
const messageType = nexus.detectType(content)
|
|
910
863
|
if (messageType) return await nexus.processMessage(content, jid, quoted)
|
|
@@ -38,6 +38,7 @@ class NexusHandler {
|
|
|
38
38
|
requestPaymentMessage: 'PAYMENT',
|
|
39
39
|
productMessage: 'PRODUCT',
|
|
40
40
|
interactiveMessage: 'INTERACTIVE',
|
|
41
|
+
interactive: 'INTERACTIVE', // Also detect 'interactive' key
|
|
41
42
|
albumMessage: 'ALBUM',
|
|
42
43
|
eventMessage: 'EVENT',
|
|
43
44
|
pollResultMessage: 'POLL_RESULT',
|
|
@@ -73,7 +74,7 @@ class NexusHandler {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
async genContent(jid, content, opts = {}) {
|
|
76
|
-
return await this.utils.
|
|
77
|
+
return await this.utils.generateWAMessage(jid, content, { ...opts, upload: this.upload })
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
async sendMsg(jid, message, opts = {}) {
|
|
@@ -164,7 +165,8 @@ class NexusHandler {
|
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
async handleInteractive(content, jid, quoted) {
|
|
167
|
-
|
|
168
|
+
// Handle both 'interactiveMessage' and 'interactive' keys
|
|
169
|
+
const i = content.interactiveMessage || content.interactive || {}
|
|
168
170
|
let media = null
|
|
169
171
|
|
|
170
172
|
if (i.thumbnail) media = await this.prepMedia({ url: i.thumbnail }, 'image')
|
|
@@ -177,10 +179,22 @@ class NexusHandler {
|
|
|
177
179
|
if (i.mimetype) media.documentMessage.mimetype = i.mimetype
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
// Handle both formats: { title, footer } and { body: {text}, footer: {text} }
|
|
183
|
+
const bodyText = i.body?.text || i.title || ''
|
|
184
|
+
const footerText = i.footer?.text || i.footer || ''
|
|
185
|
+
const interactive = { body: { text: bodyText }, footer: { text: footerText } }
|
|
181
186
|
|
|
182
187
|
if (i.buttons?.length || i.nativeFlowMessage) {
|
|
183
|
-
|
|
188
|
+
// Build nativeFlowMessage with proper structure
|
|
189
|
+
const nativeFlow = i.nativeFlowMessage || {}
|
|
190
|
+
// Only include buttons, don't add empty messageParamsJson
|
|
191
|
+
interactive.nativeFlowMessage = {
|
|
192
|
+
buttons: i.buttons || nativeFlow.buttons || []
|
|
193
|
+
}
|
|
194
|
+
// Only add messageParamsJson if explicitly provided
|
|
195
|
+
if (nativeFlow.messageParamsJson) {
|
|
196
|
+
interactive.nativeFlowMessage.messageParamsJson = nativeFlow.messageParamsJson
|
|
197
|
+
}
|
|
184
198
|
}
|
|
185
199
|
|
|
186
200
|
if (media) {
|
|
@@ -188,15 +202,23 @@ class NexusHandler {
|
|
|
188
202
|
if (media.imageMessage) headerMedia.imageMessage = media.imageMessage
|
|
189
203
|
if (media.videoMessage) headerMedia.videoMessage = media.videoMessage
|
|
190
204
|
if (media.documentMessage) headerMedia.documentMessage = media.documentMessage
|
|
191
|
-
|
|
205
|
+
// Handle both plain title string and full header object
|
|
206
|
+
const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
|
|
207
|
+
interactive.header = { title: headerTitle, hasMediaAttachment: true, ...headerMedia }
|
|
192
208
|
} else {
|
|
193
|
-
|
|
209
|
+
// Handle both plain title string and full header object
|
|
210
|
+
const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
|
|
211
|
+
interactive.header = { title: headerTitle, hasMediaAttachment: false }
|
|
194
212
|
}
|
|
195
213
|
|
|
196
214
|
const ctx = this.buildFullCtx(i.contextInfo, i.externalAdReply)
|
|
197
215
|
if (Object.keys(ctx).length) interactive.contextInfo = ctx
|
|
198
216
|
|
|
199
|
-
|
|
217
|
+
// Return interactiveMessage directly without wrapping for native flows
|
|
218
|
+
// This matches fadzzz404's approach which works correctly
|
|
219
|
+
const messageContent = { interactiveMessage: interactive }
|
|
220
|
+
|
|
221
|
+
const msg = await this.genContent(jid, messageContent, { quoted })
|
|
200
222
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
201
223
|
return msg
|
|
202
224
|
}
|
package/lib/Store/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
export * from '
|
|
3
|
-
export * from '
|
|
4
|
-
export * from '
|
|
5
|
-
export * from '
|
|
6
|
-
export { makeInMemoryStore as default } from '
|
|
2
|
+
export * from './make-cache-manager-store.js';
|
|
3
|
+
export * from './make-in-memory-store.js';
|
|
4
|
+
export * from './make-ordered-dictionary.js';
|
|
5
|
+
export * from './make-ordered-dictionary.js';
|
|
6
|
+
export { makeInMemoryStore as default } from './make-in-memory-store.js';
|
|
@@ -3,8 +3,8 @@ import * as Defaults from '../Defaults/index.js';
|
|
|
3
3
|
import { LabelAssociationType } from '../Types/LabelAssociation.js';
|
|
4
4
|
import { md5, toNumber } from '../Utils/index.js';
|
|
5
5
|
import { jidDecode, jidNormalizedUser } from '../WABinary/index.js';
|
|
6
|
-
import { makeOrderedDictionary } from '
|
|
7
|
-
import { ObjectRepository } from '
|
|
6
|
+
import { makeOrderedDictionary } from './make-ordered-dictionary.js';
|
|
7
|
+
import { ObjectRepository } from './object-repository.js';
|
|
8
8
|
|
|
9
9
|
const waChatKey = (pin) => ({
|
|
10
10
|
key: (c) => (pin ? (c.pinned ? '1' : '0') : '') + (c.archived ? '0' : '1') + (c.conversationTimestamp ? c.conversationTimestamp.toString(16).padStart(8, '0') : '') + c.id,
|
package/lib/Utils/generics.js
CHANGED
|
@@ -53,7 +53,40 @@ export const generateParticipantHashV2 = (participants) => {
|
|
|
53
53
|
const sha256Hash = sha256(Buffer.from(participants.join(''))).toString('base64');
|
|
54
54
|
return '2:' + sha256Hash.slice(0, 6);
|
|
55
55
|
};
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Encode a WhatsApp message to protobuf format
|
|
59
|
+
* Handles both raw JSON objects and pre-created protobuf objects seamlessly for ANY message type
|
|
60
|
+
* @param {Object|proto.Message} message - Raw message object or protobuf Message
|
|
61
|
+
* @returns {Buffer} Encoded message with random padding
|
|
62
|
+
*/
|
|
63
|
+
export const encodeWAMessage = (message) => {
|
|
64
|
+
try {
|
|
65
|
+
// Check if message is already a protobuf Message instance
|
|
66
|
+
if (message && typeof message === 'object' && message.$type === proto.Message) {
|
|
67
|
+
// Already a protobuf object, encode directly
|
|
68
|
+
return writeRandomPadMax16(proto.Message.encode(message).finish());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Convert raw JSON object to protobuf Message
|
|
72
|
+
if (message && typeof message === 'object') {
|
|
73
|
+
// Use proto.Message.fromObject for automatic conversion
|
|
74
|
+
const protoMessage = proto.Message.fromObject(message);
|
|
75
|
+
return writeRandomPadMax16(proto.Message.encode(protoMessage).finish());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Fallback for edge cases
|
|
79
|
+
return writeRandomPadMax16(proto.Message.encode(message).finish());
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// If conversion fails, attempt direct encoding as last resort
|
|
82
|
+
try {
|
|
83
|
+
return writeRandomPadMax16(proto.Message.encode(message).finish());
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.warn('Message encoding failed:', error.message, e.message);
|
|
86
|
+
throw new Error(`Failed to encode message: ${error.message}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
57
90
|
export const generateRegistrationId = () => {
|
|
58
91
|
return Uint16Array.from(randomBytes(2))[0] & 16383;
|
|
59
92
|
};
|
package/lib/Utils/messages.js
CHANGED
|
@@ -202,9 +202,14 @@ const handleSpecialMessages = async (message, options) => {
|
|
|
202
202
|
: message.disappearingMessagesInChat;
|
|
203
203
|
return prepareDisappearingMessageSettingContent(exp);
|
|
204
204
|
}
|
|
205
|
+
if ('extendedTextMessage' in message) { return { extendedTextMessage: message.extendedTextMessage } };
|
|
206
|
+
if ('interactiveMessage' in message) {
|
|
207
|
+
return { interactiveMessage: WAProto.Message.InteractiveMessage.create(message.interactiveMessage) };
|
|
208
|
+
}
|
|
205
209
|
return null;
|
|
206
210
|
};
|
|
207
211
|
|
|
212
|
+
|
|
208
213
|
const handleGroupInvite = async (message, options) => {
|
|
209
214
|
const m = {
|
|
210
215
|
groupInviteMessage: {
|
|
@@ -350,6 +355,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
350
355
|
}
|
|
351
356
|
};
|
|
352
357
|
else if ('requestPayment' in message) m = await handleRequestPayment(message, options);
|
|
358
|
+
else if ('extendedTextMessage' in message) { m = { extendedTextMessage: message.extendedTextMessage }; }
|
|
353
359
|
else if ('sharePhoneNumber' in message) m = { protocolMessage: { type: 4 } };
|
|
354
360
|
else if ('requestPhoneNumber' in message) m = { requestPhoneNumberMessage: {} };
|
|
355
361
|
else if ('limitSharing' in message) m = {
|
|
@@ -387,6 +393,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
387
393
|
return WAProto.Message.create(m);
|
|
388
394
|
};
|
|
389
395
|
|
|
396
|
+
|
|
390
397
|
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
391
398
|
if (!options.timestamp) options.timestamp = new Date();
|
|
392
399
|
const innerMessage = normalizeMessageContent(message);
|
|
@@ -651,5 +658,4 @@ export const assertMediaContent = (content) => {
|
|
|
651
658
|
const mediaContent = content?.documentMessage || content?.imageMessage || content?.videoMessage || content?.audioMessage || content?.stickerMessage;
|
|
652
659
|
if (!mediaContent) throw new Boom('given message is not a media message', { statusCode: 400, data: content });
|
|
653
660
|
return mediaContent;
|
|
654
|
-
};
|
|
655
|
-
|
|
661
|
+
};
|
|
@@ -25,6 +25,100 @@ export const getBinaryNodeChildBuffer = (node, childTag) => {
|
|
|
25
25
|
return child;
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
+
// Add this function after getBinaryFilteredButtons
|
|
29
|
+
export const getButtonArgs = (message) => {
|
|
30
|
+
const msgContent = message.viewOnceMessage?.message || message;
|
|
31
|
+
// Check both interactiveMessage and interactive keys
|
|
32
|
+
const interactiveMsg = msgContent.interactiveMessage || msgContent.interactive;
|
|
33
|
+
const flowMsg = interactiveMsg?.nativeFlowMessage;
|
|
34
|
+
const btnFirst = flowMsg?.buttons?.[0]?.name;
|
|
35
|
+
const specialBtns = [
|
|
36
|
+
'mpm', 'cta_catalog', 'send_location', 'call_permission_request',
|
|
37
|
+
'wa_payment_transaction_details', 'automated_greeting_message_view_catalog',
|
|
38
|
+
'open_webview', 'galaxy_message'
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const base = {
|
|
42
|
+
tag: 'biz',
|
|
43
|
+
attrs: {
|
|
44
|
+
actual_actors: '2',
|
|
45
|
+
host_storage: '2',
|
|
46
|
+
privacy_mode_ts: Math.floor(Date.now() / 1000).toString()
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Special buttons need full interactive structure
|
|
51
|
+
if (flowMsg && specialBtns.includes(btnFirst)) {
|
|
52
|
+
return {
|
|
53
|
+
...base,
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
tag: 'interactive',
|
|
57
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
58
|
+
content: [{
|
|
59
|
+
tag: 'native_flow',
|
|
60
|
+
attrs: { v: '2', name: btnFirst }
|
|
61
|
+
}]
|
|
62
|
+
},
|
|
63
|
+
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
64
|
+
]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Regular interactive/button messages
|
|
69
|
+
if (flowMsg || msgContent.buttonsMessage) {
|
|
70
|
+
return {
|
|
71
|
+
...base,
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
tag: 'interactive',
|
|
75
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
76
|
+
content: [{
|
|
77
|
+
tag: 'native_flow',
|
|
78
|
+
attrs: { v: '9', name: 'mixed' }
|
|
79
|
+
}]
|
|
80
|
+
},
|
|
81
|
+
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
82
|
+
]
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// List messages
|
|
87
|
+
if (msgContent.listMessage) {
|
|
88
|
+
return {
|
|
89
|
+
...base,
|
|
90
|
+
content: [
|
|
91
|
+
{ tag: 'list', attrs: { v: '2', type: 'product_list' } },
|
|
92
|
+
{ tag: 'quality_control', attrs: { source_type: 'third_party' } }
|
|
93
|
+
]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return base;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Add button type detection helper
|
|
101
|
+
export const getButtonType = (message) => {
|
|
102
|
+
if (message.listMessage) return 'list';
|
|
103
|
+
if (message.buttonsMessage) return 'buttons';
|
|
104
|
+
|
|
105
|
+
// Check both interactiveMessage and interactive keys
|
|
106
|
+
const interactiveMsg = message.interactiveMessage || message.interactive;
|
|
107
|
+
if (!interactiveMsg?.nativeFlowMessage) return null;
|
|
108
|
+
|
|
109
|
+
const btn = interactiveMsg?.nativeFlowMessage?.buttons?.[0]?.name;
|
|
110
|
+
if (['review_and_pay', 'review_order', 'payment_info', 'payment_status', 'payment_method'].includes(btn)) {
|
|
111
|
+
return btn;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Return 'interactive' for ANY native flow message that has buttons or nativeFlowMessage
|
|
115
|
+
if (interactiveMsg?.nativeFlowMessage?.buttons?.length || interactiveMsg?.nativeFlowMessage) {
|
|
116
|
+
return 'interactive';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return null;
|
|
120
|
+
};
|
|
121
|
+
|
|
28
122
|
export const getBinaryNodeChildString = (node, childTag) => {
|
|
29
123
|
const child = getBinaryNodeChild(node, childTag)?.content;
|
|
30
124
|
if (Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
package/lib/index.js
CHANGED
|
@@ -31,7 +31,7 @@ const banner = `
|
|
|
31
31
|
const info = `
|
|
32
32
|
┌───────────────────────────────────────────────────────────────────────┐
|
|
33
33
|
│ 📦 Package: @nexustechpro/baileys │
|
|
34
|
-
│ 🔖 Version: 1.1.
|
|
34
|
+
│ 🔖 Version: 1.1.3 │
|
|
35
35
|
│ ⚡ Status: Production Ready │
|
|
36
36
|
├───────────────────────────────────────────────────────────────────────┤
|
|
37
37
|
│ 🚀 Advanced WhatsApp Web API Client │
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexustechpro/baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.3",
|
|
5
5
|
"description": "Advanced WhatsApp Web API client with interactive messages, product catalogs, carousels, events, payments, and polls.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@cacheable/node-cache": "^1.4.0",
|
|
52
52
|
"@hapi/boom": "^9.1.3",
|
|
53
53
|
"async-mutex": "^0.5.0",
|
|
54
|
+
"axios": "^1.6.0",
|
|
54
55
|
"cache-manager": "latest",
|
|
55
56
|
"chalk": "^4.1.2",
|
|
56
57
|
"gradient-string": "^2.0.2",
|