@prototypevip/baileys 0.0.7 → 0.0.9
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/AntiBan/cli.js +177 -0
- package/lib/Socket/groups.js +26 -21
- package/lib/Socket/index.js +134 -52
- package/lib/Socket/messages-send.js +68 -5
- package/lib/Utils/ai-rich-formatter.js +256 -0
- package/lib/Utils/index.js +1 -0
- package/lib/index.js +1 -3
- package/package.json +3 -7
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* baileys-antiban CLI
|
|
4
|
+
* Usage: npx baileys-antiban <command> [options]
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import { StateManager } from './persist.js';
|
|
8
|
+
import { resolveConfig } from './presets.js';
|
|
9
|
+
import { applyPatch, unpatchFile } from './patch.js';
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const command = args[0];
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const result = {};
|
|
14
|
+
for (let i = 1; i < argv.length; i++) {
|
|
15
|
+
const arg = argv[i];
|
|
16
|
+
if (arg.startsWith('--')) {
|
|
17
|
+
const key = arg.slice(2);
|
|
18
|
+
const next = argv[i + 1];
|
|
19
|
+
if (next && !next.startsWith('--')) {
|
|
20
|
+
result[key] = next;
|
|
21
|
+
i++;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
result[key] = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function cmdStatus(opts) {
|
|
31
|
+
const statePath = opts['state'];
|
|
32
|
+
let warmupInfo = 'No state file (in-memory mode)';
|
|
33
|
+
let savedAt = 'N/A';
|
|
34
|
+
if (statePath) {
|
|
35
|
+
const mgr = new StateManager(statePath);
|
|
36
|
+
const state = mgr.load();
|
|
37
|
+
if (state) {
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
const dayMs = 86400000;
|
|
40
|
+
const currentDay = Math.floor((now - state.warmup.startedAt) / dayMs);
|
|
41
|
+
warmupInfo = state.warmup.graduated
|
|
42
|
+
? 'Graduated (warmup complete)'
|
|
43
|
+
: `Day ${currentDay + 1}, sent today: ${state.warmup.dailyCounts[currentDay] || 0}`;
|
|
44
|
+
savedAt = new Date(state.savedAt).toISOString();
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
warmupInfo = 'State file missing or corrupt';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const output = {
|
|
51
|
+
warmup: warmupInfo,
|
|
52
|
+
savedAt,
|
|
53
|
+
statePath: statePath || null,
|
|
54
|
+
};
|
|
55
|
+
if (opts['json']) {
|
|
56
|
+
console.log(JSON.stringify(output, null, 2));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log('═══ baileys-antiban status ═══');
|
|
60
|
+
console.log(`Warmup: ${output.warmup}`);
|
|
61
|
+
console.log(`Saved: ${output.savedAt}`);
|
|
62
|
+
console.log(`State: ${output.statePath || 'none'}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function cmdReset(opts) {
|
|
66
|
+
const statePath = opts['state'];
|
|
67
|
+
if (!statePath) {
|
|
68
|
+
console.error('Error: --state <path> required for reset');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
if (!fs.existsSync(statePath)) {
|
|
72
|
+
console.log('State file does not exist — nothing to reset');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
fs.unlinkSync(statePath);
|
|
76
|
+
console.log(`✅ State file deleted: ${statePath}`);
|
|
77
|
+
}
|
|
78
|
+
function cmdWarmupSimulate(opts) {
|
|
79
|
+
const days = parseInt(opts['simulate'] || '7', 10);
|
|
80
|
+
const presetName = opts['preset'] || 'conservative';
|
|
81
|
+
const cfg = resolveConfig(presetName);
|
|
82
|
+
console.log(`\nWarmup simulation — preset: ${presetName}, days: ${days}`);
|
|
83
|
+
console.log('─'.repeat(50));
|
|
84
|
+
const startDate = new Date();
|
|
85
|
+
for (let day = 0; day < days; day++) {
|
|
86
|
+
const date = new Date(startDate);
|
|
87
|
+
date.setDate(date.getDate() + day);
|
|
88
|
+
const dayName = date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' });
|
|
89
|
+
const limit = Math.round(cfg.day1Limit * Math.pow(cfg.growthFactor, day));
|
|
90
|
+
const bar = '█'.repeat(Math.min(30, Math.round(limit / 10)));
|
|
91
|
+
console.log(`Day ${String(day + 1).padStart(2)} ${dayName.padEnd(15)} ${String(limit).padStart(5)} msgs/day ${bar}`);
|
|
92
|
+
}
|
|
93
|
+
console.log('─'.repeat(50));
|
|
94
|
+
console.log(`Day ${days + 1}+: graduated (unlimited by warmup)\n`);
|
|
95
|
+
}
|
|
96
|
+
function cmdPatch(opts) {
|
|
97
|
+
const searchPaths = opts['path'] ? [opts['path']] : undefined;
|
|
98
|
+
const preset = opts['preset'] || 'conservative';
|
|
99
|
+
const minDelay = opts['min-delay'] ? parseInt(opts['min-delay']) : 1500;
|
|
100
|
+
const maxDelay = opts['max-delay'] ? parseInt(opts['max-delay']) : 4000;
|
|
101
|
+
const typingIndicator = opts['no-typing'] ? false : true;
|
|
102
|
+
const dryRun = !!opts['dry-run'];
|
|
103
|
+
const force = !!opts['force'];
|
|
104
|
+
const result = applyPatch({
|
|
105
|
+
baileysPaths: searchPaths,
|
|
106
|
+
preset,
|
|
107
|
+
minDelay,
|
|
108
|
+
maxDelay,
|
|
109
|
+
typingIndicator,
|
|
110
|
+
dryRun,
|
|
111
|
+
});
|
|
112
|
+
if (result.alreadyPatched && !force) {
|
|
113
|
+
console.log(result.message);
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
if (!result.success) {
|
|
117
|
+
console.error('✗ ' + result.message);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
console.log(result.message);
|
|
121
|
+
}
|
|
122
|
+
function cmdUnpatch(opts) {
|
|
123
|
+
const targetFile = opts['file'];
|
|
124
|
+
if (!targetFile) {
|
|
125
|
+
console.error('Usage: npx baileys-antiban unpatch --file <path-to-patched-file>');
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const result = unpatchFile(targetFile);
|
|
129
|
+
if (!result.success) {
|
|
130
|
+
console.error('✗ ' + result.message);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
console.log(result.message);
|
|
134
|
+
}
|
|
135
|
+
// Main
|
|
136
|
+
const opts = parseArgs(args);
|
|
137
|
+
switch (command) {
|
|
138
|
+
case 'status':
|
|
139
|
+
cmdStatus(opts);
|
|
140
|
+
break;
|
|
141
|
+
case 'reset':
|
|
142
|
+
cmdReset(opts);
|
|
143
|
+
break;
|
|
144
|
+
case 'warmup':
|
|
145
|
+
if (opts['simulate']) {
|
|
146
|
+
cmdWarmupSimulate(opts);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
console.error('Usage: npx baileys-antiban warmup --simulate <days> [--preset conservative|moderate|aggressive]');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
case 'patch':
|
|
154
|
+
cmdPatch(opts);
|
|
155
|
+
break;
|
|
156
|
+
case 'unpatch':
|
|
157
|
+
cmdUnpatch(opts);
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
console.log('baileys-antiban v3.0');
|
|
161
|
+
console.log('');
|
|
162
|
+
console.log('Commands:');
|
|
163
|
+
console.log(' status [--state <path>] [--json] Show warmup and health status');
|
|
164
|
+
console.log(' reset --state <path> Delete state file');
|
|
165
|
+
console.log(' warmup --simulate <days> [--preset] Show warmup schedule');
|
|
166
|
+
console.log(' patch [--path <baileys-dir>] [--preset] [--min-delay] [--max-delay] [--no-typing] [--dry-run]');
|
|
167
|
+
console.log(' unpatch --file <patched-file> Restore file from backup');
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log('Examples:');
|
|
170
|
+
console.log(' npx baileys-antiban status --state ./antiban-state.json');
|
|
171
|
+
console.log(' npx baileys-antiban warmup --simulate 7 --preset moderate');
|
|
172
|
+
console.log(' npx baileys-antiban reset --state ./antiban-state.json');
|
|
173
|
+
console.log(' npx baileys-antiban patch');
|
|
174
|
+
console.log(' npx baileys-antiban patch --path ./node_modules/@openclaw/whatsapp/node_modules/baileys');
|
|
175
|
+
console.log(' npx baileys-antiban patch --preset moderate --min-delay 1000 --max-delay 3000');
|
|
176
|
+
console.log(' npx baileys-antiban unpatch --file ./node_modules/baileys/lib/socket/index.js');
|
|
177
|
+
}
|
package/lib/Socket/groups.js
CHANGED
|
@@ -440,31 +440,36 @@ export const extractGroupMetadata = (result) => {
|
|
|
440
440
|
memberAddMode: memberAddMode,
|
|
441
441
|
participants: getBinaryNodeChildren(group, "participant").map(
|
|
442
442
|
({ attrs }) => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
443
|
+
// مهم: الـ id هنا لازم يفضل زي ما السيرفر بعته (attrs.jid) بالظبط,
|
|
444
|
+
// من غير ما نلمسه أو نبدله بـ lid/phone بديل. السبب: القيمة دي هي
|
|
445
|
+
// اللي بتتبعت زي ما هي في participantsList لـ getUSyncDevices وفي
|
|
446
|
+
// الـ addressing_mode بتاع الرسالة الصادرة (messages-send.js) —
|
|
447
|
+
// فلو الجروب addressingMode="pn" لازم كل الـ ids تكون بصيغة PN,
|
|
448
|
+
// ولو "lid" لازم تكون كلها LID. أي تبديل هنا بيسبب mismatch بين
|
|
449
|
+
// هوية المشارك والـ addressing_mode المعلن، وده اللي كان بيطلع
|
|
450
|
+
// "بيشفر"/Waiting for this message لمشاركين الـ username بالذات —
|
|
451
|
+
// مش مشكلة سيشن عشان كده افتكاك السيشن وإعادة الدخول ما كانتش بتحل حاجة.
|
|
452
|
+
// عرض الرقم/اليوزرنيم للمستخدم (لو الرقم مخفي) اتحل بالفعل في مكان
|
|
453
|
+
// تاني (resolveDisplayIdentity) وده المكان الصح ليه، مش هنا.
|
|
454
|
+
const id = attrs.jid;
|
|
454
455
|
return {
|
|
455
|
-
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
456
|
+
id,
|
|
457
|
+
// jid هنا نفس قيمة id بالظبط (مش قيمة تانية زي الكود القديم) —
|
|
458
|
+
// مُبقّاها بس عشان بعض أوامر البوت (كتم.js, مجتمع.js, muteSystem.js,
|
|
459
|
+
// context/group.js) بتقرا p.jid كـ fallback؛ ما بتأثرش على
|
|
460
|
+
// participantsList/addressing_mode لأنها زي id بالظبط دلوقتي
|
|
461
|
+
jid: id,
|
|
462
|
+
phoneNumber:
|
|
463
|
+
isLidUser(id) && isPnUser(attrs.phone_number)
|
|
464
|
+
? attrs.phone_number
|
|
465
|
+
: undefined,
|
|
466
|
+
lid: isPnUser(id) && isLidUser(attrs.lid) ? attrs.lid : undefined,
|
|
467
|
+
username: attrs.participant_username || attrs.username || undefined,
|
|
468
|
+
admin: attrs.type || null,
|
|
464
469
|
};
|
|
465
470
|
},
|
|
466
471
|
),
|
|
467
472
|
ephemeralDuration: eph ? +eph : undefined,
|
|
468
473
|
};
|
|
469
474
|
return metadata;
|
|
470
|
-
};
|
|
475
|
+
};
|
package/lib/Socket/index.js
CHANGED
|
@@ -1,79 +1,161 @@
|
|
|
1
1
|
import { DEFAULT_CONNECTION_CONFIG } from "../Defaults/index.js";
|
|
2
2
|
import { makeCommunitiesSocket } from "./communities.js";
|
|
3
|
-
import { wrapSocket, wrapSocketWithFingerprint } from "../AntiBan/wrapper.js";
|
|
4
|
-
import { resolveConfig, PRESETS } from "../AntiBan/presets.js";
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* makeWASocket({
|
|
13
|
-
*
|
|
14
|
-
* // Enable with safe defaults (conservative preset)
|
|
15
|
-
* makeWASocket({ auth, antiBan: true })
|
|
16
|
-
*
|
|
17
|
-
* // Enable with a named preset: 'conservative' | 'moderate' | 'aggressive' | 'high-volume'
|
|
18
|
-
* makeWASocket({ auth, antiBan: 'moderate' })
|
|
19
|
-
*
|
|
20
|
-
* // Enable with full custom config (see baileys-antiban README)
|
|
21
|
-
* makeWASocket({
|
|
22
|
-
* auth,
|
|
23
|
-
* antiBan: {
|
|
24
|
-
* maxPerMinute: 8,
|
|
25
|
-
* maxPerHour: 200,
|
|
26
|
-
* warmUp: { enabled: true },
|
|
27
|
-
* // ... or nested style still accepted with deprecation warning
|
|
28
|
-
* }
|
|
29
|
-
* })
|
|
30
|
-
*
|
|
31
|
-
* When enabled, the returned socket has the same API plus:
|
|
32
|
-
* sock.antiban — AntiBan instance
|
|
33
|
-
* sock.antiban.getStats() — current rate / health / risk stats
|
|
5
|
+
* Optional AntiBan — مقفول افتراضياً.
|
|
6
|
+
* لتفعيله مرّر في إعدادات makeWASocket:
|
|
7
|
+
* makeWASocket({ antiBan: true }) // moderate preset
|
|
8
|
+
* makeWASocket({ antiBan: 'conservative' }) // preset name
|
|
9
|
+
* makeWASocket({ antiBan: { maxPerMinute: 8, ... } }) // config مخصص
|
|
10
|
+
* makeWASocket({ antiBan: false }) // صراحة مقفول (الافتراضي)
|
|
34
11
|
*
|
|
35
|
-
*
|
|
36
|
-
* antiBanWarmUpState
|
|
37
|
-
* antiBanWrapOptions
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
12
|
+
* الحالة الاختيارية:
|
|
13
|
+
* antiBanWarmUpState — حالة الـ warmup المحفوظة
|
|
14
|
+
* antiBanWrapOptions — خيارات إضافية لـ wrapSocket
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
let _wrapSocket = null;
|
|
18
|
+
let _wrapSocketWithFingerprint = null;
|
|
19
|
+
let _PRESETS = {};
|
|
20
|
+
let _antiBanLoadError = null;
|
|
21
|
+
|
|
22
|
+
async function loadAntiBan() {
|
|
23
|
+
if (_wrapSocket) return true;
|
|
24
|
+
if (_antiBanLoadError) return false;
|
|
25
|
+
try {
|
|
26
|
+
const mod = await import("../AntiBan/index.js");
|
|
27
|
+
_wrapSocket = mod.wrapSocket;
|
|
28
|
+
_wrapSocketWithFingerprint = mod.wrapSocketWithFingerprint;
|
|
29
|
+
_PRESETS = mod.PRESETS || {};
|
|
30
|
+
return true;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
// fallback: try wrapper export path
|
|
33
|
+
try {
|
|
34
|
+
const wrap = await import("../AntiBan/wrapper.js");
|
|
35
|
+
const presets = await import("../AntiBan/presets.js").catch(() => ({}));
|
|
36
|
+
_wrapSocket = wrap.wrapSocket;
|
|
37
|
+
_wrapSocketWithFingerprint = wrap.wrapSocketWithFingerprint;
|
|
38
|
+
_PRESETS = presets.PRESETS || {};
|
|
39
|
+
return true;
|
|
40
|
+
} catch (e2) {
|
|
41
|
+
_antiBanLoadError = e2;
|
|
42
|
+
console.warn(
|
|
43
|
+
"[@prototypevip/baileys] AntiBan module failed to load — continuing without it:",
|
|
44
|
+
e2?.message || e2
|
|
45
|
+
);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Sync load attempt for ESM top-level (best-effort)
|
|
52
|
+
try {
|
|
53
|
+
const wrap = await import("../AntiBan/wrapper.js");
|
|
54
|
+
_wrapSocket = wrap.wrapSocket;
|
|
55
|
+
_wrapSocketWithFingerprint = wrap.wrapSocketWithFingerprint;
|
|
56
|
+
try {
|
|
57
|
+
const presets = await import("../AntiBan/presets.js");
|
|
58
|
+
_PRESETS = presets.PRESETS || {};
|
|
59
|
+
} catch {}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
_antiBanLoadError = e;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a WhatsApp socket.
|
|
66
|
+
* AntiBan مقفول افتراضياً — فعّله عبر config.antiBan
|
|
41
67
|
*/
|
|
42
68
|
const makeWASocket = (config = {}) => {
|
|
43
|
-
// Extract anti-ban related options so they don't leak into Baileys internal config
|
|
44
69
|
const {
|
|
45
|
-
antiBan,
|
|
70
|
+
antiBan = false, // مقفول افتراضياً
|
|
46
71
|
antiBanWarmUpState,
|
|
47
72
|
antiBanWrapOptions,
|
|
48
73
|
...restConfig
|
|
49
|
-
} = config;
|
|
74
|
+
} = config || {};
|
|
50
75
|
|
|
51
76
|
delete restConfig.userDevicesCache;
|
|
52
77
|
const newConfig = { ...DEFAULT_CONNECTION_CONFIG, ...restConfig };
|
|
53
78
|
|
|
54
79
|
let sock;
|
|
55
80
|
const originalGetMessage = newConfig.getMessage;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
81
|
+
if (typeof originalGetMessage === "function") {
|
|
82
|
+
newConfig.getMessage = async function (key) {
|
|
83
|
+
return originalGetMessage.call(sock || this, key);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
59
86
|
|
|
60
87
|
sock = makeCommunitiesSocket(newConfig);
|
|
61
88
|
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
89
|
+
// ── AntiBan (اختياري) ──
|
|
90
|
+
const enabled =
|
|
91
|
+
antiBan === true ||
|
|
92
|
+
(typeof antiBan === "string" && antiBan.length > 0) ||
|
|
93
|
+
(antiBan && typeof antiBan === "object");
|
|
94
|
+
|
|
95
|
+
if (enabled) {
|
|
96
|
+
if (typeof _wrapSocket !== "function") {
|
|
97
|
+
console.warn(
|
|
98
|
+
"[@prototypevip/baileys] antiBan requested but module not available — socket without protection"
|
|
99
|
+
);
|
|
100
|
+
return sock;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const antiBanConfig =
|
|
104
|
+
antiBan === true
|
|
105
|
+
? "moderate"
|
|
106
|
+
: antiBan; // string preset or object config
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
sock = _wrapSocket(
|
|
110
|
+
sock,
|
|
111
|
+
antiBanConfig,
|
|
112
|
+
antiBanWarmUpState,
|
|
113
|
+
antiBanWrapOptions || {}
|
|
114
|
+
);
|
|
115
|
+
if (newConfig.logger?.info) {
|
|
116
|
+
newConfig.logger.info(
|
|
117
|
+
{ antiBan: typeof antiBanConfig === "string" ? antiBanConfig : "custom" },
|
|
118
|
+
"AntiBan protection enabled"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.warn(
|
|
123
|
+
"[@prototypevip/baileys] AntiBan wrap failed — continuing without it:",
|
|
124
|
+
e?.message || e
|
|
125
|
+
);
|
|
71
126
|
}
|
|
72
|
-
sock = wrapSocket(sock, antibanConfig, antiBanWarmUpState, antiBanWrapOptions);
|
|
73
127
|
}
|
|
74
128
|
|
|
75
129
|
return sock;
|
|
76
130
|
};
|
|
77
131
|
|
|
132
|
+
/** Pass-through stubs when antiban is not loaded; real functions when loaded */
|
|
133
|
+
const wrapSocket = (sock, ...args) =>
|
|
134
|
+
typeof _wrapSocket === "function" ? _wrapSocket(sock, ...args) : sock;
|
|
135
|
+
|
|
136
|
+
const wrapSocketWithFingerprint = (makeSock, opts, wrapOpts) => {
|
|
137
|
+
if (typeof _wrapSocketWithFingerprint === "function") {
|
|
138
|
+
return _wrapSocketWithFingerprint(makeSock, opts, wrapOpts);
|
|
139
|
+
}
|
|
140
|
+
return typeof makeSock === "function" ? makeSock(opts || {}) : makeSock;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const PRESETS = new Proxy(
|
|
144
|
+
{},
|
|
145
|
+
{
|
|
146
|
+
get(_, prop) {
|
|
147
|
+
return _PRESETS[prop];
|
|
148
|
+
},
|
|
149
|
+
ownKeys() {
|
|
150
|
+
return Reflect.ownKeys(_PRESETS);
|
|
151
|
+
},
|
|
152
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
153
|
+
if (prop in _PRESETS) {
|
|
154
|
+
return { enumerable: true, configurable: true, value: _PRESETS[prop] };
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
|
|
78
160
|
export default makeWASocket;
|
|
79
|
-
export { wrapSocket, wrapSocketWithFingerprint, PRESETS };
|
|
161
|
+
export { makeWASocket, wrapSocket, wrapSocketWithFingerprint, PRESETS };
|
|
@@ -845,9 +845,31 @@ export const makeMessagesSocket = (config) => {
|
|
|
845
845
|
return {};
|
|
846
846
|
})(),
|
|
847
847
|
]);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
848
|
+
// نبني قائمة المشاركين + بدائل LID/PN عشان حسابات اليوزرنيم
|
|
849
|
+
// (اللي أحياناً USync بيرجع فاضي لو استعلمنا بصيغة واحدة بس)
|
|
850
|
+
const participantsList = [];
|
|
851
|
+
const seenParticipantUsers = new Set();
|
|
852
|
+
const addParticipantJid = (jid) => {
|
|
853
|
+
if (!jid || typeof jid !== "string") return;
|
|
854
|
+
const normalized = jidNormalizedUser(jid);
|
|
855
|
+
const user = jidDecode(normalized)?.user;
|
|
856
|
+
if (!user || seenParticipantUsers.has(user + ":" + (normalized.split("@")[1] || ""))) {
|
|
857
|
+
// نسمح بنفس الـ user بصيغتين مختلفتين (pn + lid) بس نمنع التكرار الحرفي
|
|
858
|
+
}
|
|
859
|
+
if (participantsList.includes(normalized) || participantsList.includes(jid)) return;
|
|
860
|
+
participantsList.push(normalized);
|
|
861
|
+
if (user) seenParticipantUsers.add(user);
|
|
862
|
+
};
|
|
863
|
+
if (groupData?.participants) {
|
|
864
|
+
for (const p of groupData.participants) {
|
|
865
|
+
addParticipantJid(p.id);
|
|
866
|
+
// بديل LID لو الـ id رقم (PN) — مهم لحسابات اليوزرنيم
|
|
867
|
+
if (p.lid) addParticipantJid(p.lid);
|
|
868
|
+
// بديل الرقم لو الـ id LID
|
|
869
|
+
if (p.phoneNumber) addParticipantJid(p.phoneNumber);
|
|
870
|
+
if (p.jid && p.jid !== p.id) addParticipantJid(p.jid);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
851
873
|
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
852
874
|
additionalAttributes = {
|
|
853
875
|
...additionalAttributes,
|
|
@@ -855,13 +877,54 @@ export const makeMessagesSocket = (config) => {
|
|
|
855
877
|
};
|
|
856
878
|
}
|
|
857
879
|
if (isStatus && statusJidList) {
|
|
858
|
-
|
|
880
|
+
for (const s of statusJidList) addParticipantJid(s);
|
|
859
881
|
}
|
|
860
|
-
|
|
882
|
+
let additionalDevices = await getUSyncDevices(
|
|
861
883
|
participantsList,
|
|
862
884
|
!!useUserDevicesCache,
|
|
863
885
|
false,
|
|
864
886
|
);
|
|
887
|
+
// لو في مشاركين معرفين في الميتاداتا ومفيش أي device ليهم في النتيجة
|
|
888
|
+
// (شائع مع username/LID)، نعيد الاستعلام من غير كاش وبمهلة أطول
|
|
889
|
+
// على الـ JIDs الناقصة فقط — من غير ما نأثر على باقي الجروب
|
|
890
|
+
if (groupData?.participants?.length) {
|
|
891
|
+
const coveredUsers = new Set(
|
|
892
|
+
additionalDevices
|
|
893
|
+
.map((d) => d.user || jidDecode(d.jid)?.user)
|
|
894
|
+
.filter(Boolean),
|
|
895
|
+
);
|
|
896
|
+
const missingJids = [];
|
|
897
|
+
for (const p of groupData.participants) {
|
|
898
|
+
const candidates = [p.id, p.lid, p.phoneNumber, p.jid].filter(Boolean);
|
|
899
|
+
const userIds = candidates
|
|
900
|
+
.map((j) => jidDecode(jidNormalizedUser(j))?.user)
|
|
901
|
+
.filter(Boolean);
|
|
902
|
+
if (userIds.some((u) => coveredUsers.has(u))) continue;
|
|
903
|
+
// جرب LID أولاً لو موجود (أحسن لليوزرنيم)، وإلا id الأصلي
|
|
904
|
+
if (p.lid) missingJids.push(jidNormalizedUser(p.lid));
|
|
905
|
+
else if (p.id) missingJids.push(jidNormalizedUser(p.id));
|
|
906
|
+
else if (p.phoneNumber) missingJids.push(jidNormalizedUser(p.phoneNumber));
|
|
907
|
+
}
|
|
908
|
+
if (missingJids.length > 0) {
|
|
909
|
+
logger.debug(
|
|
910
|
+
{ missing: missingJids.length, jids: missingJids.slice(0, 5) },
|
|
911
|
+
"retrying USync for participants with no devices (likely username/LID)",
|
|
912
|
+
);
|
|
913
|
+
try {
|
|
914
|
+
const retryDevices = await getUSyncDevices(
|
|
915
|
+
missingJids,
|
|
916
|
+
false, // no cache
|
|
917
|
+
false,
|
|
918
|
+
8000, // longer timeout
|
|
919
|
+
);
|
|
920
|
+
if (retryDevices?.length) {
|
|
921
|
+
additionalDevices = [...additionalDevices, ...retryDevices];
|
|
922
|
+
}
|
|
923
|
+
} catch (e) {
|
|
924
|
+
logger.warn({ e }, "USync retry for missing participants failed");
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
865
928
|
devices.push(...additionalDevices);
|
|
866
929
|
if (isGroup) {
|
|
867
930
|
additionalAttributes = {
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Rich Formatter helpers
|
|
3
|
+
* Extracted helpers for parsing AI responses and sending unified rich messages
|
|
4
|
+
* via AIRich (message-builder).
|
|
5
|
+
*
|
|
6
|
+
* Used by AI bot commands (Claude, Gemini, etc.)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AIRich } from './message-builder.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse a markdown table string into rows (string[][])
|
|
13
|
+
* First row is typically the header.
|
|
14
|
+
*/
|
|
15
|
+
export function parseMarkdownTable(tableString) {
|
|
16
|
+
const lines = tableString.trim().split('\n');
|
|
17
|
+
const rows = [];
|
|
18
|
+
|
|
19
|
+
for (let line of lines) {
|
|
20
|
+
line = line.trim();
|
|
21
|
+
if (line.replace(/[\s|:-]/g, '') === '') continue;
|
|
22
|
+
|
|
23
|
+
let items = line.split('|').map((c) => c.trim());
|
|
24
|
+
if (items[0] === '') items.shift();
|
|
25
|
+
if (items[items.length - 1] === '') items.pop();
|
|
26
|
+
|
|
27
|
+
if (items.length > 0) rows.push(items);
|
|
28
|
+
}
|
|
29
|
+
return rows;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Extract code blocks, tables, sources, and special action tags
|
|
34
|
+
* (exec / group / commands / db) from an AI response text.
|
|
35
|
+
*/
|
|
36
|
+
export function extractElements(text) {
|
|
37
|
+
const blocks = [];
|
|
38
|
+
const execBlocks = [];
|
|
39
|
+
const groupBlocks = [];
|
|
40
|
+
const commandsBlocks = [];
|
|
41
|
+
const dbBlocks = [];
|
|
42
|
+
const tables = [];
|
|
43
|
+
const sources = [];
|
|
44
|
+
let clean = text;
|
|
45
|
+
|
|
46
|
+
const codeRegex = /```(\w*)\n?([\s\S]*?)```/g;
|
|
47
|
+
let codeMatch;
|
|
48
|
+
while ((codeMatch = codeRegex.exec(text)) !== null) {
|
|
49
|
+
const lang = codeMatch[1].trim().toLowerCase() || 'javascript';
|
|
50
|
+
const code = codeMatch[2].trim();
|
|
51
|
+
if (code) {
|
|
52
|
+
if (lang === 'exec') execBlocks.push(code);
|
|
53
|
+
else if (lang === 'group') groupBlocks.push(code);
|
|
54
|
+
else if (lang === 'commands') commandsBlocks.push(code);
|
|
55
|
+
else if (lang === 'db') dbBlocks.push(code);
|
|
56
|
+
else blocks.push({ lang, code });
|
|
57
|
+
}
|
|
58
|
+
clean = clean.replace(codeMatch[0], '');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Safety net: model wrote [group]/[db]/[commands]/[exec] without real code fences
|
|
62
|
+
const looseTagRegex =
|
|
63
|
+
/\[(group|db|commands|exec)(?:\s+\w+)?\]\s*\n?([\s\S]*?)(?=\n\[(?:group|db|commands|exec)(?:\s+\w+)?\]|$)/gi;
|
|
64
|
+
let looseMatch;
|
|
65
|
+
while ((looseMatch = looseTagRegex.exec(clean)) !== null) {
|
|
66
|
+
const tag = looseMatch[1].toLowerCase();
|
|
67
|
+
const payload = looseMatch[2].trim();
|
|
68
|
+
if (!payload) continue;
|
|
69
|
+
if (tag === 'exec') execBlocks.push(payload);
|
|
70
|
+
else if (tag === 'group') groupBlocks.push(payload);
|
|
71
|
+
else if (tag === 'commands') commandsBlocks.push(payload);
|
|
72
|
+
else if (tag === 'db') dbBlocks.push(payload);
|
|
73
|
+
clean = clean.replace(looseMatch[0], '');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const linkRegex = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g;
|
|
77
|
+
let linkMatch;
|
|
78
|
+
const seenUrls = new Set();
|
|
79
|
+
while ((linkMatch = linkRegex.exec(clean)) !== null) {
|
|
80
|
+
const label = linkMatch[1].trim();
|
|
81
|
+
const url = linkMatch[2].trim();
|
|
82
|
+
if (!seenUrls.has(url)) {
|
|
83
|
+
seenUrls.add(url);
|
|
84
|
+
sources.push({ label, url });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
linkRegex.lastIndex = 0;
|
|
89
|
+
clean = clean.replace(linkRegex, '$1');
|
|
90
|
+
|
|
91
|
+
const lines = clean.split('\n');
|
|
92
|
+
let currentTableLines = [];
|
|
93
|
+
let newCleanLines = [];
|
|
94
|
+
let inTable = false;
|
|
95
|
+
|
|
96
|
+
for (let line of lines) {
|
|
97
|
+
if (line.trim().startsWith('|') && line.trim().endsWith('|')) {
|
|
98
|
+
inTable = true;
|
|
99
|
+
currentTableLines.push(line);
|
|
100
|
+
} else {
|
|
101
|
+
if (inTable) {
|
|
102
|
+
const parsed = parseMarkdownTable(currentTableLines.join('\n'));
|
|
103
|
+
if (parsed.length > 0) tables.push(parsed);
|
|
104
|
+
currentTableLines = [];
|
|
105
|
+
inTable = false;
|
|
106
|
+
}
|
|
107
|
+
newCleanLines.push(line);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (inTable && currentTableLines.length > 0) {
|
|
111
|
+
const parsed = parseMarkdownTable(currentTableLines.join('\n'));
|
|
112
|
+
if (parsed.length > 0) tables.push(parsed);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
clean = newCleanLines.join('\n').trim();
|
|
116
|
+
const finalMergedCode = blocks
|
|
117
|
+
.map((b) => b.code)
|
|
118
|
+
.join('\n\n// ──────────────────────────────────────────\n\n');
|
|
119
|
+
const primaryLang = blocks.length > 0 ? blocks[0].lang : 'javascript';
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
clean,
|
|
123
|
+
finalMergedCode,
|
|
124
|
+
primaryLang,
|
|
125
|
+
hasCode: blocks.length > 0,
|
|
126
|
+
tables,
|
|
127
|
+
sources,
|
|
128
|
+
execBlocks,
|
|
129
|
+
groupBlocks,
|
|
130
|
+
commandsBlocks,
|
|
131
|
+
dbBlocks,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Build and send a unified rich AI message (text + tables + code + sources + action results).
|
|
137
|
+
* Falls back to plain text if the rich send fails.
|
|
138
|
+
*/
|
|
139
|
+
export async function sendUnifiedMetaMessage(
|
|
140
|
+
prototype,
|
|
141
|
+
chatId,
|
|
142
|
+
m,
|
|
143
|
+
{
|
|
144
|
+
textOnly,
|
|
145
|
+
tables,
|
|
146
|
+
hasCode,
|
|
147
|
+
finalMergedCode,
|
|
148
|
+
primaryLang,
|
|
149
|
+
sources,
|
|
150
|
+
sig,
|
|
151
|
+
execResults,
|
|
152
|
+
groupResults,
|
|
153
|
+
commandsResults,
|
|
154
|
+
dbResults,
|
|
155
|
+
}
|
|
156
|
+
) {
|
|
157
|
+
try {
|
|
158
|
+
const rich = new AIRich(prototype);
|
|
159
|
+
|
|
160
|
+
// 1. Text
|
|
161
|
+
rich.addText((textOnly || '🤖 تم إنشاء الرد بنجاح') + (sig || ''));
|
|
162
|
+
|
|
163
|
+
// 2. Tables
|
|
164
|
+
if (tables && tables.length > 0) {
|
|
165
|
+
for (const tableRows of tables) {
|
|
166
|
+
if (Array.isArray(tableRows) && tableRows.length > 0) {
|
|
167
|
+
rich.addTable(tableRows);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 3. Colored code
|
|
173
|
+
if (hasCode && finalMergedCode) {
|
|
174
|
+
rich.addCode(primaryLang, finalMergedCode);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 4. Exec results (file edit/create/delete)
|
|
178
|
+
if (Array.isArray(execResults) && execResults.length > 0) {
|
|
179
|
+
for (const r of execResults) {
|
|
180
|
+
rich.addText(`${r.ok ? '✅' : '❌'} تنفيذ: ${r.command}`);
|
|
181
|
+
rich.addCode('bash', r.output);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 5. Group action results
|
|
186
|
+
if (Array.isArray(groupResults) && groupResults.length > 0) {
|
|
187
|
+
for (const r of groupResults) {
|
|
188
|
+
rich.addText(`${r.ok ? '✅' : '❌'} ${r.output}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 6. Commands list/count results
|
|
193
|
+
if (Array.isArray(commandsResults) && commandsResults.length > 0) {
|
|
194
|
+
for (const r of commandsResults) {
|
|
195
|
+
rich.addText(`${r.ok ? '✅' : '❌'} ${r.output}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 7. Database results
|
|
200
|
+
if (Array.isArray(dbResults) && dbResults.length > 0) {
|
|
201
|
+
for (const r of dbResults) {
|
|
202
|
+
rich.addText(`${r.ok ? '✅' : '❌'} نتيجة قاعدة البيانات:`);
|
|
203
|
+
rich.addCode('json', r.output);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 8. Sources ("See details")
|
|
208
|
+
if (Array.isArray(sources) && sources.length > 0) {
|
|
209
|
+
const defaultIcon = 'https://files.catbox.moe/9qffq1.jpg';
|
|
210
|
+
rich.addSource(sources.slice(0, 10).map((s) => [defaultIcon, s.url, s.label]));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
await rich.send(chatId, { quoted: m });
|
|
214
|
+
} catch (sendErr) {
|
|
215
|
+
console.warn('⚠️ فشل إرسال الرسالة الغنية، إرسال نسخة نصية بديلة:', sendErr.message);
|
|
216
|
+
|
|
217
|
+
let fallbackText = textOnly || '🤖 تم إنشاء الرد بنجاح';
|
|
218
|
+
if (hasCode && finalMergedCode) {
|
|
219
|
+
fallbackText += `\n\n\`\`\`${primaryLang}\n${finalMergedCode}\n\`\`\``;
|
|
220
|
+
}
|
|
221
|
+
if (Array.isArray(execResults) && execResults.length > 0) {
|
|
222
|
+
fallbackText +=
|
|
223
|
+
'\n\n' +
|
|
224
|
+
execResults
|
|
225
|
+
.map(
|
|
226
|
+
(r) =>
|
|
227
|
+
`${r.ok ? '✅' : '❌'} ${r.command}\n\`\`\`bash\n${r.output}\n\`\`\``
|
|
228
|
+
)
|
|
229
|
+
.join('\n\n');
|
|
230
|
+
}
|
|
231
|
+
if (Array.isArray(groupResults) && groupResults.length > 0) {
|
|
232
|
+
fallbackText +=
|
|
233
|
+
'\n\n' + groupResults.map((r) => `${r.ok ? '✅' : '❌'} ${r.output}`).join('\n');
|
|
234
|
+
}
|
|
235
|
+
if (Array.isArray(commandsResults) && commandsResults.length > 0) {
|
|
236
|
+
fallbackText +=
|
|
237
|
+
'\n\n' +
|
|
238
|
+
commandsResults.map((r) => `${r.ok ? '✅' : '❌'} ${r.output}`).join('\n');
|
|
239
|
+
}
|
|
240
|
+
if (Array.isArray(dbResults) && dbResults.length > 0) {
|
|
241
|
+
fallbackText +=
|
|
242
|
+
'\n\n' +
|
|
243
|
+
dbResults
|
|
244
|
+
.map((r) => `${r.ok ? '✅' : '❌'} \`\`\`json\n${r.output}\n\`\`\``)
|
|
245
|
+
.join('\n');
|
|
246
|
+
}
|
|
247
|
+
if (Array.isArray(sources) && sources.length > 0) {
|
|
248
|
+
fallbackText +=
|
|
249
|
+
`\n\n🔗 *مصادر:*\n` +
|
|
250
|
+
sources.slice(0, 10).map((s) => `• ${s.label}: ${s.url}`).join('\n');
|
|
251
|
+
}
|
|
252
|
+
fallbackText += sig || '';
|
|
253
|
+
|
|
254
|
+
await prototype.sendMessage(chatId, { text: fallbackText }, { quoted: m });
|
|
255
|
+
}
|
|
256
|
+
}
|
package/lib/Utils/index.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -9,9 +9,7 @@ export * from "./WAM/index.js";
|
|
|
9
9
|
export * from "./WAUSync/index.js";
|
|
10
10
|
export * from "./Store/cache-factory.js";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
export * from "./AntiBan/index.js";
|
|
14
|
-
export { wrapSocket, wrapSocketWithFingerprint } from "./Socket/index.js";
|
|
12
|
+
export { wrapSocket, wrapSocketWithFingerprint, PRESETS } from "./Socket/index.js";
|
|
15
13
|
|
|
16
14
|
export { makeWASocket };
|
|
17
15
|
export default makeWASocket;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prototypevip/baileys",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Baileys fork
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "Baileys fork (@prototypevip/baileys) — clean, without anti-ban",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -34,11 +34,7 @@
|
|
|
34
34
|
"whatsapp-bot",
|
|
35
35
|
"whatsapp-chat",
|
|
36
36
|
"whatsapp-group",
|
|
37
|
-
"whatsapp-web"
|
|
38
|
-
"anti-ban",
|
|
39
|
-
"rate-limit",
|
|
40
|
-
"warmup",
|
|
41
|
-
"baileys-antiban"
|
|
37
|
+
"whatsapp-web"
|
|
42
38
|
],
|
|
43
39
|
"homepage": "https://github.com/GSK-F/baileys",
|
|
44
40
|
"author": "The Prototype",
|