@fer2809fl/baileys 7.0.4 → 7.0.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 +347 -50
- package/lib/Defaults/index.js +1 -1
- package/lib/Modded/message_builder.js +2356 -0
- package/lib/Socket/chats.d.ts +14 -0
- package/lib/Socket/chats.js +48 -0
- package/lib/Socket/index.d.ts +17 -0
- package/lib/Socket/messages-send.d.ts +18 -0
- package/lib/Socket/messages-send.js +50 -2
- package/lib/Utils/anti-ban.d.ts +41 -0
- package/lib/Utils/anti-ban.js +182 -0
- package/lib/Utils/banner.d.ts +8 -0
- package/lib/Utils/banner.js +76 -0
- package/lib/Utils/bot-utils.d.ts +57 -0
- package/lib/Utils/bot-utils.js +241 -0
- package/lib/Utils/enhanced-cache.d.ts +40 -0
- package/lib/Utils/enhanced-cache.js +242 -0
- package/lib/Utils/enhanced-logger.d.ts +41 -0
- package/lib/Utils/enhanced-logger.js +185 -0
- package/lib/Utils/index.d.ts +14 -0
- package/lib/Utils/index.js +13 -0
- package/lib/Utils/lid-utils.d.ts +139 -0
- package/lib/Utils/lid-utils.js +503 -0
- package/lib/Utils/message-queue.d.ts +47 -0
- package/lib/Utils/message-queue.js +226 -0
- package/lib/Utils/rich-message-utils.d.ts +21 -0
- package/lib/Utils/rich-message-utils.js +229 -0
- package/lib/Utils/rich-messages.d.ts +52 -0
- package/lib/Utils/rich-messages.js +185 -0
- package/lib/Utils/scheduled-messages.d.ts +122 -0
- package/lib/Utils/scheduled-messages.js +289 -0
- package/lib/Utils/smart-reconnect.d.ts +48 -0
- package/lib/Utils/smart-reconnect.js +207 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
- package/lib/Utils/use-sqlite-auth-state.js +95 -0
- package/lib/VoIP/audio-feeder.d.ts +15 -0
- package/lib/VoIP/audio-feeder.js +132 -0
- package/lib/VoIP/index.js +277 -0
- package/lib/VoIP/relay-transport.d.ts +43 -0
- package/lib/VoIP/relay-transport.js +559 -0
- package/lib/VoIP/signaling.js +594 -0
- package/lib/VoIP/types.d.ts +69 -0
- package/lib/VoIP/types.js +17 -0
- package/lib/VoIP/wasm-engine.d.ts +103 -0
- package/lib/VoIP/wasm-engine.js +1214 -0
- package/lib/VoIP/worker-bootstrap.js +1042 -0
- package/lib/assets/wasm/loader.js +5 -0
- package/lib/assets/wasm/whatsapp.wasm +0 -0
- package/lib/assets/wasm/worker-modules.js +273 -0
- package/lib/index.d.ts +41 -0
- package/lib/index.js +3 -0
- package/package.json +10 -2
package/lib/Socket/chats.d.ts
CHANGED
|
@@ -76,6 +76,20 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
|
|
|
76
76
|
id: string;
|
|
77
77
|
fromMe?: boolean;
|
|
78
78
|
}[], star: boolean) => Promise<void>;
|
|
79
|
+
/** Fija o desfija un chat en la parte superior de la lista de chats. */
|
|
80
|
+
pinChat: (jid: string, pin?: boolean) => Promise<void>;
|
|
81
|
+
/** Archiva o desarchiva un chat. */
|
|
82
|
+
archiveChat: (jid: string, archive?: boolean, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
|
|
83
|
+
/** Silencia un chat hasta `muteEndTimestamp` (ms). Pasa `undefined` para quitar el silencio. */
|
|
84
|
+
muteChat: (jid: string, muteEndTimestamp?: number) => Promise<void>;
|
|
85
|
+
/** Marca un chat como leído (o no leído con `read: false`). */
|
|
86
|
+
markChatRead: (jid: string, read?: boolean, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
|
|
87
|
+
/** Atajo para marcar un chat como no leído. */
|
|
88
|
+
markChatUnread: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
|
|
89
|
+
/** Vacía el historial de un chat sin eliminar el chat. */
|
|
90
|
+
clearChat: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
|
|
91
|
+
/** Elimina un chat completo de la lista de chats. */
|
|
92
|
+
deleteChat: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
|
|
79
93
|
addOrEditQuickReply: (quickReply: QuickReplyAction) => Promise<void>;
|
|
80
94
|
removeQuickReply: (timestamp: string) => Promise<void>;
|
|
81
95
|
type: "md";
|
package/lib/Socket/chats.js
CHANGED
|
@@ -547,6 +547,47 @@ export const makeChatsSocket = (config) => {
|
|
|
547
547
|
onMutation(globalMutationMap[key]);
|
|
548
548
|
}
|
|
549
549
|
});
|
|
550
|
+
/**
|
|
551
|
+
* Fija o desfija un chat en la parte superior de la lista de chats.
|
|
552
|
+
*/
|
|
553
|
+
const pinChat = (jid, pin = true) => {
|
|
554
|
+
return chatModify({ pin }, jid);
|
|
555
|
+
};
|
|
556
|
+
/**
|
|
557
|
+
* Archiva o desarchiva un chat. Si se pasan `lastMessages`, se usan para
|
|
558
|
+
* calcular el rango de mensajes que WhatsApp debe archivar/desarchivar.
|
|
559
|
+
*/
|
|
560
|
+
const archiveChat = (jid, archive = true, lastMessages) => {
|
|
561
|
+
return chatModify({ archive, lastMessages }, jid);
|
|
562
|
+
};
|
|
563
|
+
/**
|
|
564
|
+
* Silencia un chat. `muteEndTimestamp` es el timestamp (ms) hasta el que
|
|
565
|
+
* estará silenciado; pasa `undefined`/`null` (o llama con `false`) para
|
|
566
|
+
* quitar el silencio.
|
|
567
|
+
*/
|
|
568
|
+
const muteChat = (jid, muteEndTimestamp) => {
|
|
569
|
+
return chatModify({ mute: muteEndTimestamp || undefined }, jid);
|
|
570
|
+
};
|
|
571
|
+
/**
|
|
572
|
+
* Marca un chat como leído o no leído.
|
|
573
|
+
*/
|
|
574
|
+
const markChatRead = (jid, read = true, lastMessages) => {
|
|
575
|
+
return chatModify({ markRead: read, lastMessages }, jid);
|
|
576
|
+
};
|
|
577
|
+
/** Atajo para marcar un chat como no leído. */
|
|
578
|
+
const markChatUnread = (jid, lastMessages) => markChatRead(jid, false, lastMessages);
|
|
579
|
+
/**
|
|
580
|
+
* Vacía el historial de un chat (sin eliminar el chat en sí).
|
|
581
|
+
*/
|
|
582
|
+
const clearChat = (jid, lastMessages) => {
|
|
583
|
+
return chatModify({ clear: true, lastMessages }, jid);
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Elimina un chat completo de la lista de chats.
|
|
587
|
+
*/
|
|
588
|
+
const deleteChat = (jid, lastMessages) => {
|
|
589
|
+
return chatModify({ delete: true, lastMessages }, jid);
|
|
590
|
+
};
|
|
550
591
|
/**
|
|
551
592
|
* fetch the profile picture of a user/group
|
|
552
593
|
* type = "preview" for a low res picture
|
|
@@ -1191,6 +1232,13 @@ export const makeChatsSocket = (config) => {
|
|
|
1191
1232
|
addMessageLabel,
|
|
1192
1233
|
removeMessageLabel,
|
|
1193
1234
|
star,
|
|
1235
|
+
pinChat,
|
|
1236
|
+
archiveChat,
|
|
1237
|
+
muteChat,
|
|
1238
|
+
markChatRead,
|
|
1239
|
+
markChatUnread,
|
|
1240
|
+
clearChat,
|
|
1241
|
+
deleteChat,
|
|
1194
1242
|
addOrEditQuickReply,
|
|
1195
1243
|
removeQuickReply
|
|
1196
1244
|
};
|
package/lib/Socket/index.d.ts
CHANGED
|
@@ -293,6 +293,23 @@ declare const makeWASocket: (config: UserFacingSocketConfig) => {
|
|
|
293
293
|
message: any;
|
|
294
294
|
messageId: string;
|
|
295
295
|
}>;
|
|
296
|
+
/**
|
|
297
|
+
* Envía un mensaje HTML embebido en WhatsApp. El cliente lo renderiza como
|
|
298
|
+
* un WebView sandboxed dentro del bocadillo del mensaje, usando el campo
|
|
299
|
+
* interno `GenAIaeacdsnwHtmlPrimitive` del protocolo AIRichResponseMessage.
|
|
300
|
+
*
|
|
301
|
+
* Ver `HtmlContentOptions` y el README para limitaciones y patrón recomendado.
|
|
302
|
+
*/
|
|
303
|
+
sendHtml: (
|
|
304
|
+
jid: string,
|
|
305
|
+
html: string,
|
|
306
|
+
trustedSources?: string[],
|
|
307
|
+
quoted?: any,
|
|
308
|
+
options?: import("../Utils/rich-messages.js").HtmlContentOptions,
|
|
309
|
+
) => Promise<{
|
|
310
|
+
message: any;
|
|
311
|
+
messageId: string;
|
|
312
|
+
}>;
|
|
296
313
|
sendMessage: (
|
|
297
314
|
jid: string,
|
|
298
315
|
content: import("../index.js").AnyMessageContent,
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type LatexRenderFn,
|
|
24
24
|
type MediaUploadFn,
|
|
25
25
|
type CapturedUnifiedResponse,
|
|
26
|
+
type HtmlContentOptions,
|
|
26
27
|
} from "../Utils/rich-messages.js";
|
|
27
28
|
import { type BinaryNode, type JidWithDevice } from "../WABinary/index.js";
|
|
28
29
|
import { USyncQuery } from "../WAUSync/index.js";
|
|
@@ -235,6 +236,23 @@ export declare const makeMessagesSocket: (config: SocketConfig) => {
|
|
|
235
236
|
message: any;
|
|
236
237
|
messageId: string;
|
|
237
238
|
}>;
|
|
239
|
+
/**
|
|
240
|
+
* Envía un mensaje HTML embebido en WhatsApp. El cliente lo renderiza como
|
|
241
|
+
* un WebView sandboxed dentro del bocadillo del mensaje, usando el campo
|
|
242
|
+
* interno `GenAIaeacdsnwHtmlPrimitive` del protocolo AIRichResponseMessage.
|
|
243
|
+
*
|
|
244
|
+
* Ver `HtmlContentOptions` y el README para limitaciones y patrón recomendado.
|
|
245
|
+
*/
|
|
246
|
+
sendHtml: (
|
|
247
|
+
jid: string,
|
|
248
|
+
html: string,
|
|
249
|
+
trustedSources?: string[],
|
|
250
|
+
quoted?: any,
|
|
251
|
+
options?: HtmlContentOptions,
|
|
252
|
+
) => Promise<{
|
|
253
|
+
message: any;
|
|
254
|
+
messageId: string;
|
|
255
|
+
}>;
|
|
238
256
|
sendMessage: (
|
|
239
257
|
jid: string,
|
|
240
258
|
content: AnyMessageContent,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
generateLatexInlineImageContent,
|
|
40
40
|
generateUnifiedResponseContent,
|
|
41
41
|
captureUnifiedResponse,
|
|
42
|
+
generateHtmlContent,
|
|
42
43
|
} from "../Utils/rich-messages.js";
|
|
43
44
|
import { getUrlInfo } from "../Utils/link-preview.js";
|
|
44
45
|
import { makeKeyedMutex } from "../Utils/make-mutex.js";
|
|
@@ -1022,8 +1023,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
1022
1023
|
}
|
|
1023
1024
|
const buttonType = getButtonType(message);
|
|
1024
1025
|
if (buttonType && !isNewsletter && !isStatus) {
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1026
|
+
const hasBizNode = stanza.content.some((node) => typeof node === "object" && node && node.tag === "biz");
|
|
1027
|
+
if (!hasBizNode) {
|
|
1028
|
+
const bizNodes = getAdditionalNode(buttonType);
|
|
1029
|
+
stanza.content.push(...bizNodes);
|
|
1030
|
+
}
|
|
1027
1031
|
}
|
|
1028
1032
|
logger.debug(
|
|
1029
1033
|
{ msgId },
|
|
@@ -1428,6 +1432,50 @@ export const makeMessagesSocket = (config) => {
|
|
|
1428
1432
|
await relayMessage(jid, message, { messageId });
|
|
1429
1433
|
return { message, messageId };
|
|
1430
1434
|
},
|
|
1435
|
+
/**
|
|
1436
|
+
* Envía un mensaje que el cliente de WhatsApp renderiza como un WebView
|
|
1437
|
+
* embebido dentro del bocadillo del mensaje.
|
|
1438
|
+
*
|
|
1439
|
+
* El HTML vive dentro de `unifiedResponse.data` y es renderizado por el
|
|
1440
|
+
* cliente usando el campo interno `GenAIaeacdsnwHtmlPrimitive` del
|
|
1441
|
+
* protocolo AIRichResponseMessage. El WebView puede hacer fetch únicamente
|
|
1442
|
+
* a los dominios listados en `trustedSources`.
|
|
1443
|
+
*
|
|
1444
|
+
* @param {string} jid - JID del chat destino.
|
|
1445
|
+
* @param {string} html - Contenido HTML (con `<style>`, `<body>`, `<script>`).
|
|
1446
|
+
* @param {string[]} trustedSources - Dominios permitidos para fetch/recursos.
|
|
1447
|
+
* @param {object} quoted - Mensaje a responder (opcional).
|
|
1448
|
+
* @param {object} options - Opciones adicionales (headerText, footer, fallbackText).
|
|
1449
|
+
* @returns {Promise<{ message: any, messageId: string }>}
|
|
1450
|
+
*
|
|
1451
|
+
* @example
|
|
1452
|
+
* ```js
|
|
1453
|
+
* await sock.sendHtml(
|
|
1454
|
+
* jid,
|
|
1455
|
+
* `<body><h1>Hola</h1></body>`,
|
|
1456
|
+
* ["api.tuyo.com"],
|
|
1457
|
+
* msg,
|
|
1458
|
+
* { headerText: "Demo HTML" }
|
|
1459
|
+
* );
|
|
1460
|
+
* ```
|
|
1461
|
+
*
|
|
1462
|
+
* Ver README sección "HTML embebido en WhatsApp" para limitaciones
|
|
1463
|
+
* estructurales y patrón recomendado (backend + JWT + inyección de estado).
|
|
1464
|
+
*/
|
|
1465
|
+
sendHtml: async (
|
|
1466
|
+
jid,
|
|
1467
|
+
html,
|
|
1468
|
+
trustedSources = [],
|
|
1469
|
+
quoted,
|
|
1470
|
+
options = {},
|
|
1471
|
+
) => {
|
|
1472
|
+
const { message, messageId } = generateHtmlContent(html, quoted, {
|
|
1473
|
+
...options,
|
|
1474
|
+
trustedSources,
|
|
1475
|
+
});
|
|
1476
|
+
await relayMessage(jid, message, { messageId });
|
|
1477
|
+
return { message, messageId };
|
|
1478
|
+
},
|
|
1431
1479
|
sendMessage: async (jid, content, options = {}) => {
|
|
1432
1480
|
const userJid = authState.creds.me.id;
|
|
1433
1481
|
const { quoted } = options;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const ANTI_BAN_CONFIG: {
|
|
2
|
+
MIN_MESSAGE_DELAY: number;
|
|
3
|
+
MAX_MESSAGE_DELAY: number;
|
|
4
|
+
MIN_TYPING_DELAY: number;
|
|
5
|
+
MAX_TYPING_DELAY: number;
|
|
6
|
+
GROUP_MESSAGE_DELAY: number;
|
|
7
|
+
GROUP_MAX_MESSAGES_PER_MINUTE: number;
|
|
8
|
+
BROADCAST_DELAY: number;
|
|
9
|
+
BROADCAST_MAX_PER_HOUR: number;
|
|
10
|
+
PRESENCE_UPDATE_INTERVAL: number;
|
|
11
|
+
JITTER_PERCENT: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export declare function randomDelay(min: number, max: number): number;
|
|
15
|
+
export declare function messageDelay(isGroup?: boolean): Promise<void>;
|
|
16
|
+
export declare function typingDelay(messageLength?: number): Promise<void>;
|
|
17
|
+
|
|
18
|
+
export declare class RateLimiter {
|
|
19
|
+
constructor(maxRequests: number, windowMs: number);
|
|
20
|
+
canSend(jid?: string): boolean;
|
|
21
|
+
recordSend(jid?: string): void;
|
|
22
|
+
getWaitTime(jid?: string): number;
|
|
23
|
+
waitForSlot(jid?: string): Promise<void>;
|
|
24
|
+
cleanup(): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare class PresenceManager {
|
|
28
|
+
constructor(sock: any, logger?: any);
|
|
29
|
+
simulatePresence(jid: string, action?: 'composing' | 'recording' | 'paused' | 'available' | 'unavailable'): Promise<void>;
|
|
30
|
+
sendWithPresence<T = any>(jid: string, sendFunc: () => Promise<T>, messageContent: string | object): Promise<T>;
|
|
31
|
+
startPeriodicPresence(): void;
|
|
32
|
+
stopPeriodicPresence(): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare function generateSessionFingerprint(): string;
|
|
36
|
+
export declare function isValidJid(jid: string): boolean;
|
|
37
|
+
export declare function sanitizeMessage(text: string): string;
|
|
38
|
+
|
|
39
|
+
export declare const globalRateLimiter: RateLimiter;
|
|
40
|
+
export declare const groupRateLimiter: RateLimiter;
|
|
41
|
+
export declare const broadcastRateLimiter: RateLimiter;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
|
|
3
|
+
const ANTI_BAN_CONFIG = {
|
|
4
|
+
MIN_MESSAGE_DELAY: 300,
|
|
5
|
+
MAX_MESSAGE_DELAY: 800,
|
|
6
|
+
MIN_TYPING_DELAY: 500,
|
|
7
|
+
MAX_TYPING_DELAY: 1500,
|
|
8
|
+
GROUP_MESSAGE_DELAY: 500,
|
|
9
|
+
GROUP_MAX_MESSAGES_PER_MINUTE: 40,
|
|
10
|
+
BROADCAST_DELAY: 1500,
|
|
11
|
+
BROADCAST_MAX_PER_HOUR: 300,
|
|
12
|
+
PRESENCE_UPDATE_INTERVAL: 30000,
|
|
13
|
+
JITTER_PERCENT: 0.3
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function randomDelay(min, max) {
|
|
17
|
+
const base = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
18
|
+
const jitter = base * ANTI_BAN_CONFIG.JITTER_PERCENT * (Math.random() - 0.5);
|
|
19
|
+
return Math.max(min, Math.floor(base + jitter));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function messageDelay(isGroup = false) {
|
|
23
|
+
const delay = isGroup
|
|
24
|
+
? randomDelay(ANTI_BAN_CONFIG.GROUP_MESSAGE_DELAY, ANTI_BAN_CONFIG.GROUP_MESSAGE_DELAY * 2)
|
|
25
|
+
: randomDelay(ANTI_BAN_CONFIG.MIN_MESSAGE_DELAY, ANTI_BAN_CONFIG.MAX_MESSAGE_DELAY);
|
|
26
|
+
return new Promise(resolve => setTimeout(resolve, delay));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function typingDelay(messageLength = 50) {
|
|
30
|
+
const wordsPerMinute = 50 + (Math.random() * 20 - 10);
|
|
31
|
+
const avgWordLength = 5;
|
|
32
|
+
const estimatedWords = messageLength / avgWordLength;
|
|
33
|
+
const typingTime = (estimatedWords / wordsPerMinute) * 60 * 1000;
|
|
34
|
+
const minDelay = ANTI_BAN_CONFIG.MIN_TYPING_DELAY;
|
|
35
|
+
const calculatedDelay = Math.max(minDelay, Math.min(typingTime, ANTI_BAN_CONFIG.MAX_TYPING_DELAY));
|
|
36
|
+
return new Promise(resolve => setTimeout(resolve, calculatedDelay));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class RateLimiter {
|
|
40
|
+
constructor(maxRequests, windowMs) {
|
|
41
|
+
this.maxRequests = maxRequests;
|
|
42
|
+
this.windowMs = windowMs;
|
|
43
|
+
this.requests = new Map();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
canSend(jid) {
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
const key = jid || 'global';
|
|
49
|
+
if (!this.requests.has(key)) this.requests.set(key, []);
|
|
50
|
+
const timestamps = this.requests.get(key);
|
|
51
|
+
const validTimestamps = timestamps.filter(ts => now - ts < this.windowMs);
|
|
52
|
+
this.requests.set(key, validTimestamps);
|
|
53
|
+
return validTimestamps.length < this.maxRequests;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
recordSend(jid) {
|
|
57
|
+
const key = jid || 'global';
|
|
58
|
+
if (!this.requests.has(key)) this.requests.set(key, []);
|
|
59
|
+
this.requests.get(key).push(Date.now());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getWaitTime(jid) {
|
|
63
|
+
const key = jid || 'global';
|
|
64
|
+
if (!this.requests.has(key)) return 0;
|
|
65
|
+
const timestamps = this.requests.get(key);
|
|
66
|
+
if (timestamps.length < this.maxRequests) return 0;
|
|
67
|
+
const oldestValid = timestamps[timestamps.length - this.maxRequests];
|
|
68
|
+
const waitTime = this.windowMs - (Date.now() - oldestValid);
|
|
69
|
+
return Math.max(0, waitTime);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async waitForSlot(jid) {
|
|
73
|
+
const waitTime = this.getWaitTime(jid);
|
|
74
|
+
if (waitTime > 0) {
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, waitTime + randomDelay(100, 500)));
|
|
76
|
+
}
|
|
77
|
+
this.recordSend(jid);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
cleanup() {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
for (const [key, timestamps] of this.requests.entries()) {
|
|
83
|
+
const valid = timestamps.filter(ts => now - ts < this.windowMs);
|
|
84
|
+
if (valid.length === 0) this.requests.delete(key);
|
|
85
|
+
else this.requests.set(key, valid);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
class PresenceManager {
|
|
91
|
+
constructor(sock, logger) {
|
|
92
|
+
this.sock = sock;
|
|
93
|
+
this.logger = logger;
|
|
94
|
+
this.activeChats = new Set();
|
|
95
|
+
this.presenceInterval = null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async simulatePresence(jid, action = 'composing') {
|
|
99
|
+
try {
|
|
100
|
+
await this.sock.sendPresenceUpdate(action, jid);
|
|
101
|
+
this.activeChats.add(jid);
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
this.activeChats.delete(jid);
|
|
104
|
+
this.sock.sendPresenceUpdate('paused', jid).catch(() => {});
|
|
105
|
+
}, randomDelay(3000, 8000));
|
|
106
|
+
} catch (error) {
|
|
107
|
+
this.logger?.debug({ error }, 'Error updating presence');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async sendWithPresence(jid, sendFunc, messageContent) {
|
|
112
|
+
await this.simulatePresence(jid, 'composing');
|
|
113
|
+
const length = typeof messageContent === 'string'
|
|
114
|
+
? messageContent.length
|
|
115
|
+
: JSON.stringify(messageContent).length;
|
|
116
|
+
await typingDelay(length);
|
|
117
|
+
const result = await sendFunc();
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
this.sock.sendPresenceUpdate('paused', jid).catch(() => {});
|
|
120
|
+
}, randomDelay(500, 1500));
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
startPeriodicPresence() {
|
|
125
|
+
if (this.presenceInterval) return;
|
|
126
|
+
this.presenceInterval = setInterval(() => {
|
|
127
|
+
this.sock.sendPresenceUpdate('available').catch(() => {});
|
|
128
|
+
}, ANTI_BAN_CONFIG.PRESENCE_UPDATE_INTERVAL);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
stopPeriodicPresence() {
|
|
132
|
+
if (this.presenceInterval) {
|
|
133
|
+
clearInterval(this.presenceInterval);
|
|
134
|
+
this.presenceInterval = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function generateSessionFingerprint() {
|
|
140
|
+
const timestamp = Date.now();
|
|
141
|
+
const random = randomBytes(8).toString('hex');
|
|
142
|
+
return `${timestamp}-${random}`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function isValidJid(jid) {
|
|
146
|
+
if (!jid || typeof jid !== 'string') return false;
|
|
147
|
+
const patterns = [
|
|
148
|
+
/^\d+@s\.whatsapp\.net$/,
|
|
149
|
+
/^\d+-\d+@g\.us$/,
|
|
150
|
+
/^\d+@broadcast$/,
|
|
151
|
+
/^status@broadcast$/,
|
|
152
|
+
/^\d+@lid$/
|
|
153
|
+
];
|
|
154
|
+
return patterns.some(pattern => pattern.test(jid));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function sanitizeMessage(text) {
|
|
158
|
+
if (!text || typeof text !== 'string') return text;
|
|
159
|
+
let sanitized = text.replace(/[\u200B-\u200D\uFEFF]/g, '');
|
|
160
|
+
sanitized = sanitized.replace(/\n{4,}/g, '\n\n\n');
|
|
161
|
+
sanitized = sanitized.replace(/ {3,}/g, ' ');
|
|
162
|
+
return sanitized.trim();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const globalRateLimiter = new RateLimiter(100, 60000);
|
|
166
|
+
const groupRateLimiter = new RateLimiter(20, 60000);
|
|
167
|
+
const broadcastRateLimiter = new RateLimiter(200, 3600000);
|
|
168
|
+
|
|
169
|
+
export {
|
|
170
|
+
ANTI_BAN_CONFIG,
|
|
171
|
+
randomDelay,
|
|
172
|
+
messageDelay,
|
|
173
|
+
typingDelay,
|
|
174
|
+
RateLimiter,
|
|
175
|
+
PresenceManager,
|
|
176
|
+
generateSessionFingerprint,
|
|
177
|
+
isValidJid,
|
|
178
|
+
sanitizeMessage,
|
|
179
|
+
globalRateLimiter,
|
|
180
|
+
groupRateLimiter,
|
|
181
|
+
broadcastRateLimiter
|
|
182
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
const BAILEYS_LOGO = [
|
|
5
|
+
' ⠠⡀ ⡀',
|
|
6
|
+
' ⠱⣄⠘⣆',
|
|
7
|
+
' ⣀ ⢢⣤⣀⣦⣄⡀⠙⣶⡘⢷⣄',
|
|
8
|
+
' ⣀⣀⣨⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣯⣿⣷⣄',
|
|
9
|
+
' ⢀⣽⣿⣿⣿⣿⠟⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣿⣿⣷⣄',
|
|
10
|
+
' ⠘⣻⣿⣿⡿⠋ ⠈⠙⢿⣿⣿⣿⣿⢿⣷⡀',
|
|
11
|
+
' ⣴⣿⣿⣿⡇ ⠙⣿⣿⣿⣷⣽⣷⣄',
|
|
12
|
+
' ⣾⣿⣿⣇ ⠈⠛⢿⣿⣿⣿⣯⠁',
|
|
13
|
+
' ⠐⠛⢿⣿⣿⣦⡀ ⠉⠻⣿⣿⣷⣄⡀',
|
|
14
|
+
' ⠘⠟⠿⣿⣿⣦⣀ ⠈⢿⣿⣿⠇',
|
|
15
|
+
' ⠈⠙⠻⣿⣷⣦⣄⡀ ⡼⠟⠋',
|
|
16
|
+
' ⠈⠙⠻⢿⣷⣶⣄',
|
|
17
|
+
' ⠈⠙⠻⣿⣦⡀',
|
|
18
|
+
' ⠙⢿⡄',
|
|
19
|
+
' ⢻⡄',
|
|
20
|
+
' ⠈⡇'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const GRADIENT_FROM = [167, 85, 247];
|
|
24
|
+
const GRADIENT_TO = [34, 211, 238];
|
|
25
|
+
|
|
26
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
27
|
+
|
|
28
|
+
const supportsColor = stream => {
|
|
29
|
+
if (process.env.NO_COLOR || process.env.NODE_DISABLE_COLORS) return false;
|
|
30
|
+
if (process.env.FORCE_COLOR) return true;
|
|
31
|
+
return !!stream.isTTY;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const paint = (text, t) => {
|
|
35
|
+
const [r, g, b] = GRADIENT_FROM.map((from, i) => Math.round(from + (GRADIENT_TO[i] - from) * t));
|
|
36
|
+
return `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const buildLines = version => [
|
|
40
|
+
'',
|
|
41
|
+
...BAILEYS_LOGO,
|
|
42
|
+
'',
|
|
43
|
+
` @fer2809fl/baileys v${version}`,
|
|
44
|
+
' github.com/Fer2809fl/Bail',
|
|
45
|
+
''
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
let alreadyPrinted = false;
|
|
49
|
+
|
|
50
|
+
const printBanner = async (options = {}) => {
|
|
51
|
+
let version = '2.0';
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8'));
|
|
54
|
+
version = pkg.version || version;
|
|
55
|
+
} catch {}
|
|
56
|
+
const {
|
|
57
|
+
stream = process.stdout,
|
|
58
|
+
frameMs = 45,
|
|
59
|
+
once = true
|
|
60
|
+
} = options;
|
|
61
|
+
if (once && alreadyPrinted) return;
|
|
62
|
+
alreadyPrinted = true;
|
|
63
|
+
const animate = options.animate !== undefined ? options.animate : !!stream.isTTY;
|
|
64
|
+
const color = supportsColor(stream);
|
|
65
|
+
const lines = buildLines(version);
|
|
66
|
+
for (let i = 0; i < lines.length; i++) {
|
|
67
|
+
const t = i / (lines.length - 1);
|
|
68
|
+
stream.write((color ? paint(lines[i], t) : lines[i]) + '\n');
|
|
69
|
+
if (animate) await sleep(frameMs);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
BAILEYS_LOGO,
|
|
75
|
+
printBanner
|
|
76
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare function parseCommand(text: string, prefix?: string): {
|
|
2
|
+
isCommand: boolean;
|
|
3
|
+
command?: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
fullArgs?: string;
|
|
6
|
+
flags?: Record<string, string | boolean>;
|
|
7
|
+
raw?: string;
|
|
8
|
+
prefix?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export declare function extractMentions(message: any): string[];
|
|
12
|
+
export declare function extractText(message: any): string;
|
|
13
|
+
export declare function extractQuotedMessage(message: any): {
|
|
14
|
+
message: any;
|
|
15
|
+
stanzaId?: string;
|
|
16
|
+
participant?: string;
|
|
17
|
+
remoteJid?: string;
|
|
18
|
+
text: string;
|
|
19
|
+
} | null;
|
|
20
|
+
|
|
21
|
+
export declare function isGroupAdmin(sock: any, jid: string, participantJid: string): Promise<boolean>;
|
|
22
|
+
export declare function isBotAdmin(sock: any, jid: string): Promise<boolean>;
|
|
23
|
+
export declare function getSenderJid(msg: any): string;
|
|
24
|
+
export declare function formatJid(jid: string): string;
|
|
25
|
+
export declare function generateMessageId(): string;
|
|
26
|
+
export declare function truncateText(text: string, maxLength?: number, suffix?: string): string;
|
|
27
|
+
export declare function escapeMarkdown(text: string): string;
|
|
28
|
+
export declare function formatPhoneNumber(jid: string): string;
|
|
29
|
+
|
|
30
|
+
export declare class CooldownManager {
|
|
31
|
+
isOnCooldown(key: string, cooldownMs: number): boolean;
|
|
32
|
+
setCooldown(key: string, cooldownMs: number): void;
|
|
33
|
+
getRemainingTime(key: string): number;
|
|
34
|
+
cleanup(): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare class PermissionManager {
|
|
38
|
+
constructor(config?: { owners?: string[]; admins?: string[]; banned?: string[]; premiums?: string[] });
|
|
39
|
+
isOwner(jid: string): boolean;
|
|
40
|
+
isAdmin(jid: string): boolean;
|
|
41
|
+
isBanned(jid: string): boolean;
|
|
42
|
+
isPremium(jid: string): boolean;
|
|
43
|
+
addOwner(jid: string): void;
|
|
44
|
+
removeOwner(jid: string): void;
|
|
45
|
+
addAdmin(jid: string): void;
|
|
46
|
+
removeAdmin(jid: string): void;
|
|
47
|
+
ban(jid: string): void;
|
|
48
|
+
unban(jid: string): void;
|
|
49
|
+
addPremium(jid: string): void;
|
|
50
|
+
removePremium(jid: string): void;
|
|
51
|
+
toJSON(): { owners: string[]; admins: string[]; banned: string[]; premiums: string[] };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export declare function createReply(options: { text: string; mentions?: string[]; quoted?: any }): { text: string; mentions?: string[]; quoted?: any };
|
|
55
|
+
export declare function parseTime(timeStr: string): number;
|
|
56
|
+
export declare function formatDuration(ms: number): string;
|
|
57
|
+
export declare function sendFast(sock: any, jid: string, content: string | object, opts?: { quoted?: any; markRead?: boolean }): Promise<any>;
|