@aseppxyzz12/baileys 1.1.8
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/LICENSE +25 -0
- package/README.md +2579 -0
- package/WAProto/AICommon/AICommon.js +19396 -0
- package/WAProto/AICommon/AICommon.proto +820 -0
- package/WAProto/Adv/Adv.js +1137 -0
- package/WAProto/Adv/Adv.proto +42 -0
- package/WAProto/BotMetadata/BotMetadata.js +8975 -0
- package/WAProto/BotMetadata/BotMetadata.proto +484 -0
- package/WAProto/Cert/Cert.js +893 -0
- package/WAProto/Cert/Cert.proto +30 -0
- package/WAProto/ChatLockSettings/ChatLockSettings.js +673 -0
- package/WAProto/ChatLockSettings/ChatLockSettings.proto +9 -0
- package/WAProto/CompanionReg/CompanionReg.js +2457 -0
- package/WAProto/CompanionReg/CompanionReg.proto +103 -0
- package/WAProto/DeviceCapabilities/DeviceCapabilities.js +846 -0
- package/WAProto/DeviceCapabilities/DeviceCapabilities.proto +38 -0
- package/WAProto/E2E/E2E.js +78728 -0
- package/WAProto/E2E/E2E.proto +1970 -0
- package/WAProto/Ephemeral/Ephemeral.js +143 -0
- package/WAProto/Ephemeral/Ephemeral.proto +7 -0
- package/WAProto/HistorySync/HistorySync.js +95931 -0
- package/WAProto/HistorySync/HistorySync.proto +229 -0
- package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.js +414 -0
- package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.proto +13 -0
- package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.js +980 -0
- package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.proto +38 -0
- package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.js +81185 -0
- package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.proto +88 -0
- package/WAProto/MmsRetry/MmsRetry.js +310 -0
- package/WAProto/MmsRetry/MmsRetry.proto +19 -0
- package/WAProto/Protocol/Protocol.js +399 -0
- package/WAProto/Protocol/Protocol.proto +22 -0
- package/WAProto/Reporting/Reporting.js +535 -0
- package/WAProto/Reporting/Reporting.proto +22 -0
- package/WAProto/ServerSync/ServerSync.js +1830 -0
- package/WAProto/ServerSync/ServerSync.proto +70 -0
- package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.js +3267 -0
- package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.proto +95 -0
- package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.js +1140 -0
- package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.proto +44 -0
- package/WAProto/StatusAttributions/StatusAttributions.js +1604 -0
- package/WAProto/StatusAttributions/StatusAttributions.proto +89 -0
- package/WAProto/SyncAction/SyncAction.js +17424 -0
- package/WAProto/SyncAction/SyncAction.proto +663 -0
- package/WAProto/UserPassword/UserPassword.js +544 -0
- package/WAProto/UserPassword/UserPassword.proto +28 -0
- package/WAProto/VnameCert/VnameCert.js +1466 -0
- package/WAProto/VnameCert/VnameCert.proto +65 -0
- package/WAProto/Wa6/Wa6.js +4601 -0
- package/WAProto/Wa6/Wa6.proto +241 -0
- package/WAProto/Web/Web.js +90819 -0
- package/WAProto/Web/Web.proto +605 -0
- package/WAProto/index.js +30 -0
- package/engine-requirements.js +9 -0
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/connection.js +39 -0
- package/lib/Defaults/constants.js +50 -0
- package/lib/Defaults/history.js +13 -0
- package/lib/Defaults/index.js +36 -0
- package/lib/Defaults/media.js +43 -0
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Defaults/prefix.js +12 -0
- package/lib/Function/Download/tiktok.js +19 -0
- package/lib/Function/Tools/bypass.js +19 -0
- package/lib/Function/index.js +13 -0
- package/lib/Signal/Group/ciphertext-message.js +14 -0
- package/lib/Signal/Group/group-session-builder.js +46 -0
- package/lib/Signal/Group/group_cipher.js +104 -0
- package/lib/Signal/Group/index.js +42 -0
- package/lib/Signal/Group/keyhelper.js +21 -0
- package/lib/Signal/Group/queue-job.js +57 -0
- package/lib/Signal/Group/sender-chain-key.js +34 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
- package/lib/Signal/Group/sender-key-message.js +78 -0
- package/lib/Signal/Group/sender-key-name.js +49 -0
- package/lib/Signal/Group/sender-key-record.js +45 -0
- package/lib/Signal/Group/sender-key-state.js +100 -0
- package/lib/Signal/Group/sender-message-key.js +28 -0
- package/lib/Signal/libsignal.js +364 -0
- package/lib/Signal/lid-mapping.js +164 -0
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.js +31 -0
- package/lib/Socket/Client/mobile-socket-client.js +65 -0
- package/lib/Socket/Client/types.js +12 -0
- package/lib/Socket/Client/web-socket-client.js +62 -0
- package/lib/Socket/Client/websocket.js +67 -0
- package/lib/Socket/business.js +291 -0
- package/lib/Socket/chats.js +874 -0
- package/lib/Socket/community.js +454 -0
- package/lib/Socket/dugong.js +658 -0
- package/lib/Socket/groups.js +357 -0
- package/lib/Socket/index.js +13 -0
- package/lib/Socket/messages-recv.js +1509 -0
- package/lib/Socket/messages-send.js +1505 -0
- package/lib/Socket/mex.js +54 -0
- package/lib/Socket/newsletter.js +171 -0
- package/lib/Socket/registration.js +167 -0
- package/lib/Socket/rich-content.js +279 -0
- package/lib/Socket/socket.js +905 -0
- package/lib/Socket/username.js +157 -0
- package/lib/Socket/usync.js +70 -0
- package/lib/Store/index.js +37 -0
- package/lib/Store/keyed-db.js +114 -0
- package/lib/Store/make-cache-manager-store.js +77 -0
- package/lib/Store/make-in-memory-store.js +423 -0
- package/lib/Store/make-ordered-dictionary.js +78 -0
- package/lib/Store/object-repository.js +26 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +10 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +4 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +40 -0
- package/lib/Types/MexUpdates.js +15 -0
- package/lib/Types/Newsletter.js +32 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/State.js +9 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +60 -0
- package/lib/Utils/auth-utils.js +256 -0
- package/lib/Utils/baileys-event-stream.js +63 -0
- package/lib/Utils/bot-toolkit.js +455 -0
- package/lib/Utils/browser-utils.js +29 -0
- package/lib/Utils/business.js +233 -0
- package/lib/Utils/chat-utils.js +904 -0
- package/lib/Utils/companion-reg-client-utils.js +41 -0
- package/lib/Utils/crypto.js +144 -0
- package/lib/Utils/decode-wa-message.js +305 -0
- package/lib/Utils/event-buffer.js +555 -0
- package/lib/Utils/generics.js +411 -0
- package/lib/Utils/history.js +100 -0
- package/lib/Utils/identity-change-handler.js +53 -0
- package/lib/Utils/index.js +57 -0
- package/lib/Utils/link-preview.js +76 -0
- package/lib/Utils/logger.js +4 -0
- package/lib/Utils/lt-hash.js +45 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +289 -0
- package/lib/Utils/message-retry-manager.js +134 -0
- package/lib/Utils/messages-media.js +806 -0
- package/lib/Utils/messages.js +1908 -0
- package/lib/Utils/noise-handler.js +157 -0
- package/lib/Utils/offline-node-processor.js +42 -0
- package/lib/Utils/pre-key-manager.js +86 -0
- package/lib/Utils/process-message.js +814 -0
- package/lib/Utils/reporting-utils.js +264 -0
- package/lib/Utils/signal.js +183 -0
- package/lib/Utils/stanza-ack.js +36 -0
- package/lib/Utils/sync-action-utils.js +52 -0
- package/lib/Utils/tc-token-utils.js +167 -0
- package/lib/Utils/use-multi-file-auth-state.js +104 -0
- package/lib/Utils/validate-connection.js +229 -0
- package/lib/Utils/vialeys-event-stream.js +41 -0
- package/lib/WABinary/constants.js +1308 -0
- package/lib/WABinary/decode.js +233 -0
- package/lib/WABinary/encode.js +212 -0
- package/lib/WABinary/generic-utils.js +124 -0
- package/lib/WABinary/index.js +36 -0
- package/lib/WABinary/jid-utils.js +101 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +12 -0
- package/lib/WAM/constants.js +20491 -0
- package/lib/WAM/encode.js +148 -0
- package/lib/WAM/index.js +34 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +62 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +50 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +25 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +24 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +24 -0
- package/lib/WAUSync/Protocols/index.js +38 -0
- package/lib/WAUSync/USyncQuery.js +97 -0
- package/lib/WAUSync/USyncUser.js +33 -0
- package/lib/WAUSync/index.js +34 -0
- package/lib/index.js +113 -0
- package/lib/messages-send.js +1496 -0
- package/package.json +100 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeBotToolkit = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A grab-bag of small, self-contained quality-of-life features that don't
|
|
6
|
+
* exist in upstream Baileys or other forks. None of this touches the core
|
|
7
|
+
* decrypt/encrypt/socket pipeline - it's all additive, attached to the
|
|
8
|
+
* socket's return object.
|
|
9
|
+
*/
|
|
10
|
+
const makeBotToolkit = (conn, logger) => {
|
|
11
|
+
const startedAt = Date.now();
|
|
12
|
+
const seenMessageIds = new Map(); // id -> timestamp, used for dedup
|
|
13
|
+
const rateLimitBuckets = new Map(); // `${jid}:${key}` -> last timestamp
|
|
14
|
+
const DEDUP_TTL_MS = 60 * 1000;
|
|
15
|
+
const dedupCleanupEvery = 200;
|
|
16
|
+
let dedupCounter = 0;
|
|
17
|
+
/** internal: drop old entries from the dedup map so it doesn't grow forever */
|
|
18
|
+
const cleanupDedup = () => {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
for (const [id, ts] of seenMessageIds) {
|
|
21
|
+
if (now - ts > DEDUP_TTL_MS) {
|
|
22
|
+
seenMessageIds.delete(id);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const pollTallies = new Map(); // pollMsgId -> { question, options, votes: Map<voterJid, optionIndex[]>, listening }
|
|
27
|
+
const groupMetaCache = new Map(); // jid -> { data, fetchedAt }
|
|
28
|
+
const GROUP_META_TTL_MS = 60 * 1000;
|
|
29
|
+
return {
|
|
30
|
+
/**
|
|
31
|
+
* Releases bot-toolkit's own internal state (poll trackers, group
|
|
32
|
+
* metadata cache, dedup/rate-limit maps). Call this when a session
|
|
33
|
+
* ends/logs out, alongside the socket's own cleanup, so nothing in
|
|
34
|
+
* this toolkit keeps holding memory for a dead connection.
|
|
35
|
+
*/
|
|
36
|
+
destroy() {
|
|
37
|
+
seenMessageIds.clear();
|
|
38
|
+
rateLimitBuckets.clear();
|
|
39
|
+
groupMetaCache.clear();
|
|
40
|
+
pollTallies.clear();
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a user is an admin/superadmin in a group, using the
|
|
44
|
+
* cached metadata getter above so repeated checks (every message in
|
|
45
|
+
* a busy group) don't keep re-fetching from WA.
|
|
46
|
+
*/
|
|
47
|
+
async isGroupAdmin(groupJid, userJid) {
|
|
48
|
+
const meta = await this.getCachedGroupMetadata(groupJid);
|
|
49
|
+
const participant = meta?.participants?.find((p) => p.id === userJid || p.jid === userJid);
|
|
50
|
+
return participant?.admin === 'admin' || participant?.admin === 'superadmin';
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* Splits long text into WhatsApp-safe chunks and sends them one
|
|
54
|
+
* after another (with a small delay), so a long AI response or log
|
|
55
|
+
* dump doesn't get truncated or rejected for being too long.
|
|
56
|
+
*/
|
|
57
|
+
async sendChunked(jid, text, options = {}, maxLen = 4000, delayMs = 800) {
|
|
58
|
+
if (!text || text.length <= maxLen) {
|
|
59
|
+
return [await conn.sendMessage(jid, { text, ...options })];
|
|
60
|
+
}
|
|
61
|
+
const chunks = [];
|
|
62
|
+
for (let i = 0; i < text.length; i += maxLen) {
|
|
63
|
+
chunks.push(text.slice(i, i + maxLen));
|
|
64
|
+
}
|
|
65
|
+
const sent = [];
|
|
66
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
67
|
+
sent.push(await conn.sendMessage(jid, { text: chunks[i], ...options }));
|
|
68
|
+
if (i < chunks.length - 1) {
|
|
69
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return sent;
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Shows "typing..." presence for a bit before actually sending - makes
|
|
76
|
+
* the bot feel less robotic. `typingMs` is how long to show typing
|
|
77
|
+
* before the message goes out.
|
|
78
|
+
*/
|
|
79
|
+
async sendWithTyping(jid, content, options = {}, typingMs = 1200) {
|
|
80
|
+
try {
|
|
81
|
+
await conn.sendPresenceUpdate('composing', jid);
|
|
82
|
+
await new Promise((r) => setTimeout(r, typingMs));
|
|
83
|
+
await conn.sendPresenceUpdate('paused', jid);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
logger.debug({ err }, 'sendWithTyping: presence update failed, sending anyway');
|
|
87
|
+
}
|
|
88
|
+
return conn.sendMessage(jid, content, options);
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* sendMessage with automatic retry on transient failures (network
|
|
92
|
+
* blips, rate limiting) - NOT for permanent failures like invalid
|
|
93
|
+
* jid. Retries up to `retries` times with growing delay.
|
|
94
|
+
*/
|
|
95
|
+
async sendMessageSafe(jid, content, options = {}, retries = 3) {
|
|
96
|
+
let lastErr;
|
|
97
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
98
|
+
try {
|
|
99
|
+
return await conn.sendMessage(jid, content, options);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
lastErr = err;
|
|
103
|
+
const isLikelyTransient = /(timed out|ECONNRESET|ETIMEDOUT|rate-overlimit|Internal Server Error)/i.test(err?.message || '');
|
|
104
|
+
if (!isLikelyTransient || attempt === retries) {
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
logger.debug({ attempt, err }, 'sendMessageSafe: transient failure, retrying');
|
|
108
|
+
await new Promise((r) => setTimeout(r, 1000 * attempt));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
throw lastErr;
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* Downloads any URL into a Buffer - the one-liner you end up writing
|
|
115
|
+
* in every plugin that needs to grab an image/file from the internet
|
|
116
|
+
* before sending it.
|
|
117
|
+
*/
|
|
118
|
+
async getBuffer(url, opts = {}) {
|
|
119
|
+
const res = await fetch(url, opts);
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
throw new Error(`getBuffer: HTTP ${res.status} fetching ${url}`);
|
|
122
|
+
}
|
|
123
|
+
const arrBuf = await res.arrayBuffer();
|
|
124
|
+
return Buffer.from(arrBuf);
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* Downloads a URL and sends it as the right message type automatically,
|
|
128
|
+
* based on the response's content-type (falls back to sniffing the
|
|
129
|
+
* file extension in the URL if the server doesn't send one).
|
|
130
|
+
* await conn.sendFileFromUrl(jid, 'https://example.com/cat.png', { caption: 'meow' })
|
|
131
|
+
*/
|
|
132
|
+
async sendFileFromUrl(jid, url, options = {}) {
|
|
133
|
+
const res = await fetch(url);
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
throw new Error(`sendFileFromUrl: HTTP ${res.status} fetching ${url}`);
|
|
136
|
+
}
|
|
137
|
+
const contentType = res.headers.get('content-type') || '';
|
|
138
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
139
|
+
let contentKey = 'document';
|
|
140
|
+
if (contentType.startsWith('image/') || /\.(jpe?g|png|webp|gif)$/i.test(url)) {
|
|
141
|
+
contentKey = 'image';
|
|
142
|
+
}
|
|
143
|
+
else if (contentType.startsWith('video/') || /\.(mp4|mkv|mov)$/i.test(url)) {
|
|
144
|
+
contentKey = 'video';
|
|
145
|
+
}
|
|
146
|
+
else if (contentType.startsWith('audio/') || /\.(mp3|ogg|wav|m4a)$/i.test(url)) {
|
|
147
|
+
contentKey = 'audio';
|
|
148
|
+
}
|
|
149
|
+
const content = { [contentKey]: buffer, ...options };
|
|
150
|
+
if (contentKey === 'document' && !content.mimetype) {
|
|
151
|
+
content.mimetype = contentType || 'application/octet-stream';
|
|
152
|
+
}
|
|
153
|
+
return conn.sendMessage(jid, content, options.messageOptions || {});
|
|
154
|
+
},
|
|
155
|
+
/** human-readable uptime string, e.g. "2h 14m 9s", for status/.ping commands */
|
|
156
|
+
uptimeString() {
|
|
157
|
+
const ms = Date.now() - startedAt;
|
|
158
|
+
const s = Math.floor(ms / 1000) % 60;
|
|
159
|
+
const m = Math.floor(ms / 60000) % 60;
|
|
160
|
+
const h = Math.floor(ms / 3600000);
|
|
161
|
+
return `${h}h ${m}m ${s}s`;
|
|
162
|
+
},
|
|
163
|
+
/**
|
|
164
|
+
* Cached groupMetadata - avoids hammering WA's servers when you call
|
|
165
|
+
* groupMetadata() repeatedly for the same group in a short window
|
|
166
|
+
* (e.g. every message handler checking admin status). Falls back to
|
|
167
|
+
* a real fetch automatically once the cache entry goes stale.
|
|
168
|
+
*/
|
|
169
|
+
async getCachedGroupMetadata(jid, ttlMs = GROUP_META_TTL_MS) {
|
|
170
|
+
const cached = groupMetaCache.get(jid);
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
if (cached && now - cached.fetchedAt < ttlMs) {
|
|
173
|
+
return cached.data;
|
|
174
|
+
}
|
|
175
|
+
const data = await conn.groupMetadata(jid);
|
|
176
|
+
groupMetaCache.set(jid, { data, fetchedAt: now });
|
|
177
|
+
return data;
|
|
178
|
+
},
|
|
179
|
+
/** drops a single group (or the whole cache if no jid given) from getCachedGroupMetadata's cache */
|
|
180
|
+
invalidateGroupMetadataCache(jid) {
|
|
181
|
+
if (jid) {
|
|
182
|
+
groupMetaCache.delete(jid);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
groupMetaCache.clear();
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* Scans message text for @628xxx-style mentions and returns the jids
|
|
190
|
+
* it found, so you don't have to write the regex yourself every time
|
|
191
|
+
* you want to build a mentions-enabled message.
|
|
192
|
+
* const mentions = conn.parseMentions('hai @6281234567890 apa kabar')
|
|
193
|
+
* conn.sendMessage(jid, { text, mentions })
|
|
194
|
+
*/
|
|
195
|
+
parseMentions(text) {
|
|
196
|
+
if (!text) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const matches = text.match(/@(\d{5,16})/g) || [];
|
|
200
|
+
return matches.map((m) => `${m.slice(1)}@s.whatsapp.net`);
|
|
201
|
+
},
|
|
202
|
+
/**
|
|
203
|
+
* Normalizes a loosely-formatted phone number into a proper WA jid.
|
|
204
|
+
* Strips spaces/dashes/plus/parens, and turns a leading "0" into "62"
|
|
205
|
+
* (change defaultCountryCode if most of your users aren't Indonesian).
|
|
206
|
+
* conn.formatJid('0812-3456-7890') -> '6281234567890@s.whatsapp.net'
|
|
207
|
+
* conn.formatJid('+62 812 3456 7890') -> '6281234567890@s.whatsapp.net'
|
|
208
|
+
*/
|
|
209
|
+
formatJid(numberOrJid, defaultCountryCode = '62') {
|
|
210
|
+
if (!numberOrJid) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
if (numberOrJid.includes('@')) {
|
|
214
|
+
return numberOrJid;
|
|
215
|
+
}
|
|
216
|
+
let digits = numberOrJid.replace(/[^\d]/g, '');
|
|
217
|
+
if (digits.startsWith('0')) {
|
|
218
|
+
digits = defaultCountryCode + digits.slice(1);
|
|
219
|
+
}
|
|
220
|
+
return `${digits}@s.whatsapp.net`;
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* Unwraps a view-once message (any version) and returns the real
|
|
224
|
+
* underlying content (imageMessage/videoMessage/audioMessage), so you
|
|
225
|
+
* can download/save it before it's gone. Returns null if the message
|
|
226
|
+
* isn't a view-once wrapper.
|
|
227
|
+
*/
|
|
228
|
+
extractViewOnce(message) {
|
|
229
|
+
if (!message) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const wrapped = message.viewOnceMessage?.message
|
|
233
|
+
|| message.viewOnceMessageV2?.message
|
|
234
|
+
|| message.viewOnceMessageV2Extension?.message
|
|
235
|
+
|| null;
|
|
236
|
+
if (!wrapped) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
const innerType = Object.keys(wrapped)[0];
|
|
240
|
+
return { type: innerType, content: wrapped[innerType], message: wrapped };
|
|
241
|
+
},
|
|
242
|
+
/**
|
|
243
|
+
* Downloads whatever media is in a message (image/video/audio/sticker/
|
|
244
|
+
* document), automatically unwrapping view-once first if needed.
|
|
245
|
+
* Returns { buffer, type } or null if there's no media to download.
|
|
246
|
+
*/
|
|
247
|
+
async downloadAnyMedia(message) {
|
|
248
|
+
let target = message;
|
|
249
|
+
const unwrapped = (message?.viewOnceMessage?.message)
|
|
250
|
+
|| (message?.viewOnceMessageV2?.message)
|
|
251
|
+
|| (message?.viewOnceMessageV2Extension?.message);
|
|
252
|
+
if (unwrapped) {
|
|
253
|
+
target = unwrapped;
|
|
254
|
+
}
|
|
255
|
+
const mediaTypes = ['imageMessage', 'videoMessage', 'audioMessage', 'stickerMessage', 'documentMessage', 'documentWithCaptionMessage'];
|
|
256
|
+
const foundType = mediaTypes.find((t) => target?.[t]);
|
|
257
|
+
if (!foundType) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const { downloadMediaMessage } = require('./messages');
|
|
261
|
+
const buffer = await downloadMediaMessage({ message: target }, 'buffer', {});
|
|
262
|
+
return { buffer, type: foundType };
|
|
263
|
+
},
|
|
264
|
+
/**
|
|
265
|
+
* Starts auto-tracking votes for a poll you just sent, so you don't have
|
|
266
|
+
* to manually call getAggregateVotesInPollMessage yourself every time.
|
|
267
|
+
* `pollMsg` is the message object returned by sendMessage() for a poll.
|
|
268
|
+
* Returns a live snapshot getter; call .stop() to stop tracking it.
|
|
269
|
+
*/
|
|
270
|
+
trackPoll(pollMsg) {
|
|
271
|
+
var _a, _b, _c;
|
|
272
|
+
const pollMsgId = pollMsg?.key?.id;
|
|
273
|
+
if (!pollMsgId) {
|
|
274
|
+
throw new Error('trackPoll: pollMsg.key.id is missing');
|
|
275
|
+
}
|
|
276
|
+
const pollCreation = (_c = (_b = (_a = pollMsg.message) === null || _a === void 0 ? void 0 : _a.pollCreationMessage) !== null && _b !== void 0 ? _b : pollMsg.message?.pollCreationMessageV3) !== null && _c !== void 0 ? _c : pollMsg.message?.pollCreationMessageV2;
|
|
277
|
+
const options = (pollCreation?.options || []).map((o) => o.optionName);
|
|
278
|
+
const state = { question: pollCreation?.name || '', options, voters: new Map() };
|
|
279
|
+
pollTallies.set(pollMsgId, state);
|
|
280
|
+
const onUpdate = (updates) => {
|
|
281
|
+
for (const { key, update } of updates) {
|
|
282
|
+
const pollUpdates = update?.pollUpdates;
|
|
283
|
+
if (!pollUpdates || key?.id !== pollMsgId) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const { getAggregateVotesInPollMessage } = require('./messages');
|
|
288
|
+
const tally = getAggregateVotesInPollMessage({ message: pollMsg.message, pollUpdates }, conn.authState?.creds?.me?.id);
|
|
289
|
+
state.lastTally = tally;
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
logger.error({ err }, 'trackPoll: failed to aggregate votes');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
conn.ev.on('messages.update', onUpdate);
|
|
297
|
+
return {
|
|
298
|
+
getResults: () => state.lastTally || options.map((name) => ({ name, voters: [] })),
|
|
299
|
+
stop: () => {
|
|
300
|
+
conn.ev.off('messages.update', onUpdate);
|
|
301
|
+
pollTallies.delete(pollMsgId);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
/**
|
|
306
|
+
* One-stop JID inspector: decodes a jid and tells you exactly what
|
|
307
|
+
* kind of address it is, without having to juggle isJidGroup/isLidUser/
|
|
308
|
+
* isJidUser/jidDecode yourself every time.
|
|
309
|
+
*/
|
|
310
|
+
resolveJid(jid) {
|
|
311
|
+
var _a;
|
|
312
|
+
const { isJidUser, isLidUser, isJidGroup, isJidBroadcast, isJidStatusBroadcast, isJidNewsLetter, isHostedPnUser, isHostedLidUser, jidDecode: decode } = require('../WABinary');
|
|
313
|
+
const decoded = decode(jid);
|
|
314
|
+
let kind = 'unknown';
|
|
315
|
+
if (isJidStatusBroadcast(jid)) {
|
|
316
|
+
kind = 'status';
|
|
317
|
+
}
|
|
318
|
+
else if (isJidNewsLetter(jid)) {
|
|
319
|
+
kind = 'newsletter';
|
|
320
|
+
}
|
|
321
|
+
else if (isJidGroup(jid)) {
|
|
322
|
+
kind = 'group';
|
|
323
|
+
}
|
|
324
|
+
else if (isJidBroadcast(jid)) {
|
|
325
|
+
kind = 'broadcast';
|
|
326
|
+
}
|
|
327
|
+
else if (isHostedLidUser(jid)) {
|
|
328
|
+
kind = 'hosted-lid';
|
|
329
|
+
}
|
|
330
|
+
else if (isLidUser(jid)) {
|
|
331
|
+
kind = 'lid';
|
|
332
|
+
}
|
|
333
|
+
else if (isHostedPnUser(jid)) {
|
|
334
|
+
kind = 'hosted-pn';
|
|
335
|
+
}
|
|
336
|
+
else if (isJidUser(jid)) {
|
|
337
|
+
kind = 'pn';
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
jid,
|
|
341
|
+
kind,
|
|
342
|
+
user: (_a = decoded === null || decoded === void 0 ? void 0 : decoded.user) !== null && _a !== void 0 ? _a : null,
|
|
343
|
+
device: (decoded === null || decoded === void 0 ? void 0 : decoded.device) !== undefined ? decoded.device : null,
|
|
344
|
+
server: (decoded === null || decoded === void 0 ? void 0 : decoded.server) || null,
|
|
345
|
+
isLid: kind === 'lid' || kind === 'hosted-lid',
|
|
346
|
+
isPn: kind === 'pn' || kind === 'hosted-pn'
|
|
347
|
+
};
|
|
348
|
+
},
|
|
349
|
+
/**
|
|
350
|
+
* Returns a one-shot snapshot of the connection's health - useful for a
|
|
351
|
+
* `.status` style command without having to manually gather state from
|
|
352
|
+
* five different places.
|
|
353
|
+
*/
|
|
354
|
+
healthCheck() {
|
|
355
|
+
var _a, _b, _c, _d, _e, _f;
|
|
356
|
+
const wsState = (_b = (_a = conn.ws) === null || _a === void 0 ? void 0 : _a.socket) === null || _b === void 0 ? void 0 : _b.readyState;
|
|
357
|
+
const wsStateNames = { 0: 'CONNECTING', 1: 'OPEN', 2: 'CLOSING', 3: 'CLOSED' };
|
|
358
|
+
return {
|
|
359
|
+
uptimeMs: Date.now() - startedAt,
|
|
360
|
+
wsState: wsStateNames[wsState] || 'UNKNOWN',
|
|
361
|
+
isOnline: wsState === 1,
|
|
362
|
+
me: ((_c = conn.authState) === null || _c === void 0 ? void 0 : _c.creds.me) || null,
|
|
363
|
+
lidMappingCacheSize: (_f = (_e = (_d = conn.signalRepository) === null || _d === void 0 ? void 0 : _d.lidMapping) === null || _e === void 0 ? void 0 : _e.mappingCache) === null || _f === void 0 ? void 0 : _f.size,
|
|
364
|
+
dedupTracked: seenMessageIds.size,
|
|
365
|
+
rateLimitBucketsTracked: rateLimitBuckets.size
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
/**
|
|
369
|
+
* Like `conn.ev.on`, but the handler is isolated: a throw or rejection
|
|
370
|
+
* is caught & logged instead of bubbling up, and an optional timeout
|
|
371
|
+
* guards against a handler that hangs forever (e.g. a stuck network
|
|
372
|
+
* call inside a plugin) from quietly blocking that listener's "lane".
|
|
373
|
+
*
|
|
374
|
+
* @param event event name, e.g. 'messages.upsert'
|
|
375
|
+
* @param handler (data) => any | Promise<any>
|
|
376
|
+
* @param opts.timeoutMs if set, logs a warning if the handler doesn't
|
|
377
|
+
* settle within this time (does NOT kill it -
|
|
378
|
+
* JS can't cancel a running sync/async function -
|
|
379
|
+
* it's a "hey this looks stuck" signal only)
|
|
380
|
+
*/
|
|
381
|
+
onSafe(event, handler, opts = {}) {
|
|
382
|
+
const { timeoutMs } = opts;
|
|
383
|
+
const wrapped = (data) => {
|
|
384
|
+
let timeoutHandle;
|
|
385
|
+
try {
|
|
386
|
+
const result = handler(data);
|
|
387
|
+
if (result && typeof result.then === 'function') {
|
|
388
|
+
if (timeoutMs) {
|
|
389
|
+
timeoutHandle = setTimeout(() => {
|
|
390
|
+
logger.warn({ event, timeoutMs }, 'onSafe handler is taking unusually long (still running)');
|
|
391
|
+
}, timeoutMs);
|
|
392
|
+
}
|
|
393
|
+
result
|
|
394
|
+
.catch((err) => {
|
|
395
|
+
logger.error({ err, event }, 'onSafe: unhandled async error, ignored');
|
|
396
|
+
})
|
|
397
|
+
.finally(() => {
|
|
398
|
+
if (timeoutHandle) {
|
|
399
|
+
clearTimeout(timeoutHandle);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
logger.error({ err, event }, 'onSafe: error, ignored');
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
conn.ev.on(event, wrapped);
|
|
409
|
+
return () => conn.ev.off(event, wrapped);
|
|
410
|
+
},
|
|
411
|
+
/**
|
|
412
|
+
* Returns true if this message id has already been seen recently
|
|
413
|
+
* (within DEDUP_TTL_MS). Marks it as seen either way. Use at the top
|
|
414
|
+
* of your messages.upsert handler to skip WA's occasional duplicate
|
|
415
|
+
* delivery (reconnect races etc.) without writing your own cache.
|
|
416
|
+
*/
|
|
417
|
+
isDuplicateMessage(messageId) {
|
|
418
|
+
if (!messageId) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
const seen = seenMessageIds.has(messageId);
|
|
422
|
+
seenMessageIds.set(messageId, Date.now());
|
|
423
|
+
dedupCounter += 1;
|
|
424
|
+
if (dedupCounter % dedupCleanupEvery === 0) {
|
|
425
|
+
cleanupDedup();
|
|
426
|
+
}
|
|
427
|
+
return seen;
|
|
428
|
+
},
|
|
429
|
+
/**
|
|
430
|
+
* Simple per-(jid, key) cooldown helper. Returns true if the action
|
|
431
|
+
* is currently rate-limited (i.e. you should NOT proceed), false if
|
|
432
|
+
* it's OK to go ahead (and marks the timestamp).
|
|
433
|
+
* if (conn.isRateLimited(m.chat, 'menu', 5000)) return;
|
|
434
|
+
*/
|
|
435
|
+
isRateLimited(jid, key, windowMs) {
|
|
436
|
+
const bucketKey = `${jid}:${key}`;
|
|
437
|
+
const now = Date.now();
|
|
438
|
+
const last = rateLimitBuckets.get(bucketKey);
|
|
439
|
+
if (last && now - last < windowMs) {
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
rateLimitBuckets.set(bucketKey, now);
|
|
443
|
+
return false;
|
|
444
|
+
},
|
|
445
|
+
/**
|
|
446
|
+
* Asks an Anthropic model to help debug an error / snippet against
|
|
447
|
+
* THIS fork's actual Baileys source, so suggestions are grounded in
|
|
448
|
+
* what's really in your codebase instead of generic upstream advice.
|
|
449
|
+
* Wire this up to whatever command prefix you like in your own bot
|
|
450
|
+
* dispatcher (e.g. `.aimahiru`) - this function only does the actual
|
|
451
|
+
* call + prompt shaping, not command parsing.
|
|
452
|
+
*/
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
exports.makeBotToolkit = makeBotToolkit;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { platform: platform, release: release } = require("os");
|
|
4
|
+
const { proto: proto } = require("../../WAProto");
|
|
5
|
+
const PLATFORM_MAP = {
|
|
6
|
+
aix: "AIX",
|
|
7
|
+
darwin: "Mac OS",
|
|
8
|
+
win32: "Windows",
|
|
9
|
+
android: "Android",
|
|
10
|
+
freebsd: "FreeBSD",
|
|
11
|
+
openbsd: "OpenBSD",
|
|
12
|
+
sunos: "Solaris",
|
|
13
|
+
linux: undefined,
|
|
14
|
+
haiku: undefined,
|
|
15
|
+
cygwin: undefined,
|
|
16
|
+
netbsd: undefined,
|
|
17
|
+
};
|
|
18
|
+
const Browsers = {
|
|
19
|
+
ubuntu: (browser) => ["Ubuntu", browser, "22.04.4"],
|
|
20
|
+
macOS: (browser) => ["Mac OS", browser, "14.4.1"],
|
|
21
|
+
baileys: (browser) => ["Baileys", browser, "6.5.0"],
|
|
22
|
+
windows: (browser) => ["Windows", browser, "10.0.22631"],
|
|
23
|
+
appropriate: (browser) => [PLATFORM_MAP[platform()] || "Ubuntu", browser, release()],
|
|
24
|
+
};
|
|
25
|
+
const getPlatformId = (browser) => {
|
|
26
|
+
const platformType = proto.DeviceProps.PlatformType[browser.toUpperCase()];
|
|
27
|
+
return platformType ? platformType.toString() : "1";
|
|
28
|
+
};
|
|
29
|
+
module.exports = { Browsers: Browsers, getPlatformId: getPlatformId };
|