lyxe-baileys 1.1.0 → 2.0.0
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 +74 -0
- package/package.json +1 -1
- package/src/Lyxe/dashboard.js +301 -0
- package/src/Lyxe/group-bypass.js +87 -0
- package/src/Lyxe/index.d.ts +46 -1
- package/src/Lyxe/index.js +52 -2
- package/src/Lyxe/radar.js +95 -0
- package/src/Lyxe/telegram-bridge.js +188 -0
- package/src/Lyxe/vault.js +138 -0
- package/src/Lyxe/video-note.js +21 -0
- package/src/Lyxe/view-once.js +96 -25
- package/src/Socket/Client/proxy-agent.js +188 -0
- package/src/Socket/Client/websocket.js +60 -53
- package/src/index.d.ts +8 -1
package/README.md
CHANGED
|
@@ -203,6 +203,80 @@ manager.on('messages.upsert', ({ sessionId, upsert, sock }) => {
|
|
|
203
203
|
})
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
+
### 7. 🛡️ Built-in Proxy & TLS Chrome Spoofer (Anti-Banned Connection Shield)
|
|
207
|
+
Hubungkan bot melalui proxy HTTP, HTTPS, atau SOCKS5 dengan fingerprint TLS Chrome 131+ asli untuk meminimalkan deteksi bot dari server WhatsApp:
|
|
208
|
+
```javascript
|
|
209
|
+
import makeWASocket, { useMultiFileAuthState } from 'lyxe-baileys'
|
|
210
|
+
|
|
211
|
+
const { state, saveCreds } = await useMultiFileAuthState('./session')
|
|
212
|
+
|
|
213
|
+
// Mendukung HTTP, HTTPS, atau SOCKS5 Proxy
|
|
214
|
+
const sock = makeWASocket({
|
|
215
|
+
auth: state,
|
|
216
|
+
proxy: 'socks5://user:password@127.0.0.1:1080' // atau 'http://proxyhost:8080'
|
|
217
|
+
})
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 8. 🏷️ Bypass Pembatasan Privasi Grup (Privacy 403 Bypass Engine)
|
|
221
|
+
Menambahkan peserta ke grup meskipun nomor target mengunci privasi grup (*Error 403*). Engine otomatis mengambil tiket server resmi dan mengirimkan kartu undangan GroupInviteMessage (V4) 1-klik langsung ke chat pribadinya:
|
|
222
|
+
```javascript
|
|
223
|
+
// Otomatis bypass jika nomor target mengunci privasi grupnya
|
|
224
|
+
const results = await sock.groupAddWithBypass(groupJid, ['6281234567890@s.whatsapp.net'], {
|
|
225
|
+
caption: 'Undangan resmi bergabung ke grup kami!'
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
console.log(results)
|
|
229
|
+
// Output: [{ jid: '...', status: '403_bypassed_with_invite', bypassed: true, inviteCode: '...' }]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 9. 🗄️ Immortal Media & Message Vault (Anti-Delete Otomatis)
|
|
233
|
+
Simpan semua pesan, media (gambar, video, audio, VN), dan pesan View-Once yang masuk secara otomatis ke brankas lokal sebelum sempat ditarik pengirim:
|
|
234
|
+
```javascript
|
|
235
|
+
// Mengambil statistik dari vault
|
|
236
|
+
const stats = sock.vault.getStats()
|
|
237
|
+
console.log(`Vault menyimpan ${stats.totalMessages} pesan dan ${stats.totalMedia} berkas media.`)
|
|
238
|
+
|
|
239
|
+
// Ambil riwayat chat tertentu dari brankas
|
|
240
|
+
const chatHistory = sock.vault.getMessages('628123456789@s.whatsapp.net', 20)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 10. 🚀 Built-in Web Cockpit & Live Dashboard
|
|
244
|
+
Pantau status koneksi bot, statistik memori, uptime, kirim pesan uji coba, dan lihat pesan masuk secara live real-time via browser tanpa dependensi tambahan (zero-dependency native HTTP):
|
|
245
|
+
```javascript
|
|
246
|
+
// Nyalakan Web Cockpit Dashboard di port pilihan
|
|
247
|
+
sock.startDashboard(3000)
|
|
248
|
+
// Buka browser Anda: http://localhost:3000
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 11. ✈️ Telegram to WhatsApp Auto-Bridge
|
|
252
|
+
Hubungkan bot Telegram langsung ke WhatsApp! Pesan teks, foto, video, dokumen, dan voice note dari Telegram otomatis diteruskan ke nomor atau grup WhatsApp yang ditentukan:
|
|
253
|
+
```javascript
|
|
254
|
+
const bridge = sock.bridgeTelegram({
|
|
255
|
+
botToken: '123456789:ABCdefGHIjklMNOpqrSTUvwxYZ',
|
|
256
|
+
targetWaJid: '120363023123456789@g.us', // JID WhatsApp tujuan
|
|
257
|
+
allowedTelegramChatIds: ['-1001234567890'], // (Opsional) filter ID Telegram
|
|
258
|
+
autoDownloadMedia: true
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
bridge.start()
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 12. 🛰️ Presence & Online Stalker Radar (Stealth Subscriptions)
|
|
265
|
+
Lacak status online / offline target secara diam-diam tanpa perlu membuka obrolan mereka menggunakan stanza presence WhatsApp tingkat rendah:
|
|
266
|
+
```javascript
|
|
267
|
+
// Pantau target secara real-time
|
|
268
|
+
await sock.trackPresence('628123456789@s.whatsapp.net', (presence) => {
|
|
269
|
+
console.log(`[RADAR] ${presence.jid} sekarang: ${presence.status} pada ${new Date(presence.lastSeen).toLocaleTimeString()}`)
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 13. ⚪ Circular Video Note PTV (WhatsApp Video Bulat)
|
|
274
|
+
Kirim video note berbentuk bulat layaknya pesan video instan di Telegram (Push-To-Video / PTV):
|
|
275
|
+
```javascript
|
|
276
|
+
// Kirim video note bulat instan
|
|
277
|
+
await sock.sendVideoNote(jid, './video.mp4')
|
|
278
|
+
```
|
|
279
|
+
|
|
206
280
|
---
|
|
207
281
|
|
|
208
282
|
## 📚 Daftar Isi
|
package/package.json
CHANGED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Built-in Web Cockpit & Live Monitor Dashboard (Zero Dependency).
|
|
6
|
+
* Membuka antarmuka grafis di browser untuk memantau status bot, chat masuk, dan kontrol bot.
|
|
7
|
+
*/
|
|
8
|
+
export class LyxeDashboard {
|
|
9
|
+
constructor(sock, options = {}) {
|
|
10
|
+
this.sock = sock;
|
|
11
|
+
this.port = Number(options.port) || 3000;
|
|
12
|
+
this.recentMessages = [];
|
|
13
|
+
this.maxMessages = 40;
|
|
14
|
+
this.server = null;
|
|
15
|
+
this.qrCode = null;
|
|
16
|
+
this.connectionStatus = 'connecting';
|
|
17
|
+
this.startTime = Date.now();
|
|
18
|
+
|
|
19
|
+
this.bindEvents();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
bindEvents() {
|
|
23
|
+
if (!this.sock) return;
|
|
24
|
+
|
|
25
|
+
this.sock.ev.on('connection.update', (update) => {
|
|
26
|
+
if (update.qr) {
|
|
27
|
+
this.qrCode = update.qr;
|
|
28
|
+
}
|
|
29
|
+
if (update.connection) {
|
|
30
|
+
this.connectionStatus = update.connection;
|
|
31
|
+
if (update.connection === 'open') {
|
|
32
|
+
this.qrCode = null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
this.sock.ev.on('messages.upsert', ({ messages }) => {
|
|
38
|
+
for (const m of messages) {
|
|
39
|
+
if (!m.message) continue;
|
|
40
|
+
const text = m.message.conversation ||
|
|
41
|
+
m.message.extendedTextMessage?.text ||
|
|
42
|
+
m.message.imageMessage?.caption ||
|
|
43
|
+
(m.message.imageMessage ? '[Foto]' : m.message.videoMessage ? '[Video]' : '[Media]');
|
|
44
|
+
const from = m.key.remoteJid;
|
|
45
|
+
const sender = m.key.participant || from;
|
|
46
|
+
this.recentMessages.unshift({
|
|
47
|
+
id: m.key.id,
|
|
48
|
+
from,
|
|
49
|
+
sender: sender ? sender.split('@')[0] : 'Unknown',
|
|
50
|
+
fromMe: Boolean(m.key.fromMe),
|
|
51
|
+
text,
|
|
52
|
+
time: new Date().toLocaleTimeString('id-ID')
|
|
53
|
+
});
|
|
54
|
+
if (this.recentMessages.length > this.maxMessages) {
|
|
55
|
+
this.recentMessages.pop();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
start() {
|
|
62
|
+
if (this.server) return;
|
|
63
|
+
|
|
64
|
+
this.server = http.createServer((req, res) => {
|
|
65
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
66
|
+
|
|
67
|
+
// CORS headers
|
|
68
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
69
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
70
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
71
|
+
|
|
72
|
+
if (req.method === 'OPTIONS') {
|
|
73
|
+
res.writeHead(204);
|
|
74
|
+
res.end();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (url.pathname === '/api/status') {
|
|
79
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
80
|
+
res.end(JSON.stringify({
|
|
81
|
+
status: this.connectionStatus,
|
|
82
|
+
user: this.sock?.user || null,
|
|
83
|
+
uptime: Math.floor((Date.now() - this.startTime) / 1000),
|
|
84
|
+
memory: {
|
|
85
|
+
totalMB: Math.round(os.totalmem() / 1024 / 1024),
|
|
86
|
+
freeMB: Math.round(os.freemem() / 1024 / 1024),
|
|
87
|
+
processMB: Math.round(process.memoryUsage().rss / 1024 / 1024)
|
|
88
|
+
},
|
|
89
|
+
qrCode: this.qrCode
|
|
90
|
+
}));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (url.pathname === '/api/messages') {
|
|
95
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
96
|
+
res.end(JSON.stringify(this.recentMessages));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (url.pathname === '/api/send' && req.method === 'POST') {
|
|
101
|
+
let body = '';
|
|
102
|
+
req.on('data', chunk => body += chunk);
|
|
103
|
+
req.on('end', async () => {
|
|
104
|
+
try {
|
|
105
|
+
const { jid, text } = JSON.parse(body);
|
|
106
|
+
if (!jid || !text) {
|
|
107
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
108
|
+
return res.end(JSON.stringify({ error: 'JID dan Text wajib diisi' }));
|
|
109
|
+
}
|
|
110
|
+
const formattedJid = jid.includes('@') ? jid : `${jid.replace(/[^0-9]/g, '')}@s.whatsapp.net`;
|
|
111
|
+
const sent = await this.sock.sendMessage(formattedJid, { text });
|
|
112
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
113
|
+
res.end(JSON.stringify({ success: true, id: sent?.key?.id }));
|
|
114
|
+
} catch (e) {
|
|
115
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
116
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// HTML Frontend Dashboard
|
|
123
|
+
if (url.pathname === '/' || url.pathname === '/index.html') {
|
|
124
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
125
|
+
res.end(this.renderHTML());
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
130
|
+
res.end('Not Found');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
this.server.listen(this.port, () => {
|
|
134
|
+
console.log(`\n🎛️ [Lyxe Cockpit] Web Dashboard aktif di: http://localhost:${this.port}\n`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
stop() {
|
|
139
|
+
if (this.server) {
|
|
140
|
+
this.server.close();
|
|
141
|
+
this.server = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
renderHTML() {
|
|
146
|
+
return `<!DOCTYPE html>
|
|
147
|
+
<html lang="id">
|
|
148
|
+
<head>
|
|
149
|
+
<meta charset="UTF-8">
|
|
150
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
151
|
+
<title>Lyxe Baileys - Live Cockpit Dashboard</title>
|
|
152
|
+
<style>
|
|
153
|
+
:root {
|
|
154
|
+
--bg: #0f172a;
|
|
155
|
+
--card: #1e293b;
|
|
156
|
+
--border: #334155;
|
|
157
|
+
--primary: #8b5cf6;
|
|
158
|
+
--accent: #06b6d4;
|
|
159
|
+
--text: #f8fafc;
|
|
160
|
+
--muted: #94a3b8;
|
|
161
|
+
--green: #10b981;
|
|
162
|
+
--red: #ef4444;
|
|
163
|
+
}
|
|
164
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
165
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--text); padding: 24px; }
|
|
166
|
+
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid var(--border); }
|
|
167
|
+
.header h1 { font-size: 24px; font-weight: 700; background: linear-gradient(135deg, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
|
168
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
|
169
|
+
.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.2); }
|
|
170
|
+
.card h3 { font-size: 14px; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; letter-spacing: 0.5px; }
|
|
171
|
+
.card .val { font-size: 24px; font-weight: bold; }
|
|
172
|
+
.badge { display: inline-block; padding: 4px 10px; border-radius: 9999px; font-size: 12px; font-weight: 600; text-transform: uppercase; }
|
|
173
|
+
.badge-open { background: rgba(16, 185, 129, 0.2); color: var(--green); }
|
|
174
|
+
.badge-connecting { background: rgba(6, 182, 212, 0.2); color: var(--accent); }
|
|
175
|
+
.badge-close { background: rgba(239, 68, 68, 0.2); color: var(--red); }
|
|
176
|
+
.chat-container { display: grid; grid-template-columns: 1fr 340px; gap: 20px; }
|
|
177
|
+
.chat-box { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; height: 500px; display: flex; flex-direction: column; }
|
|
178
|
+
.messages-list { flex: 1; overflow-y: auto; padding-right: 8px; }
|
|
179
|
+
.msg-item { padding: 10px; border-bottom: 1px solid rgba(255,255,255,0.05); font-size: 14px; }
|
|
180
|
+
.msg-item .meta { display: flex; justify-content: space-between; font-size: 11px; color: var(--muted); margin-bottom: 4px; }
|
|
181
|
+
.send-box { display: flex; flex-direction: column; gap: 12px; }
|
|
182
|
+
input, textarea, button { width: 100%; padding: 10px 14px; background: #0f172a; border: 1px solid var(--border); border-radius: 8px; color: #fff; font-size: 14px; }
|
|
183
|
+
input:focus, textarea:focus { outline: none; border-color: var(--primary); }
|
|
184
|
+
button { background: var(--primary); color: #fff; font-weight: 600; border: none; cursor: pointer; transition: 0.2s; }
|
|
185
|
+
button:hover { background: #7c3aed; }
|
|
186
|
+
@media (max-width: 800px) { .chat-container { grid-template-columns: 1fr; } }
|
|
187
|
+
</style>
|
|
188
|
+
</head>
|
|
189
|
+
<body>
|
|
190
|
+
<div class="header">
|
|
191
|
+
<div>
|
|
192
|
+
<h1>⚡ LYXE BAILEYS COCKPIT</h1>
|
|
193
|
+
<p style="color: var(--muted); font-size: 13px;">Realtime Bot Engine & Protocol Telemetry</p>
|
|
194
|
+
</div>
|
|
195
|
+
<div id="badge-status" class="badge badge-connecting">Connecting...</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div class="grid">
|
|
199
|
+
<div class="card">
|
|
200
|
+
<h3>Nomor WhatsApp</h3>
|
|
201
|
+
<div id="val-user" class="val">-</div>
|
|
202
|
+
</div>
|
|
203
|
+
<div class="card">
|
|
204
|
+
<h3>Penggunaan RAM</h3>
|
|
205
|
+
<div id="val-ram" class="val">-</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="card">
|
|
208
|
+
<h3>Uptime Bot</h3>
|
|
209
|
+
<div id="val-uptime" class="val">-</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div class="chat-container">
|
|
214
|
+
<div class="chat-box">
|
|
215
|
+
<h3 style="margin-bottom: 12px;">📡 LIVE MESSAGE STREAM</h3>
|
|
216
|
+
<div id="messages-list" class="messages-list">
|
|
217
|
+
<p style="color: var(--muted); text-align: center; margin-top: 40px;">Menunggu pesan masuk...</p>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<div class="card send-box">
|
|
222
|
+
<h3>🚀 TEST SEND MESSAGE</h3>
|
|
223
|
+
<input id="input-jid" placeholder="Nomor WA (contoh: 628123xxx)" />
|
|
224
|
+
<textarea id="input-text" rows="5" placeholder="Ketik pesan yang ingin dikirim..."></textarea>
|
|
225
|
+
<button onclick="sendMessage()">KIRIM PESAN</button>
|
|
226
|
+
<p id="send-status" style="font-size: 12px; text-align: center; color: var(--muted);"></p>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<script>
|
|
231
|
+
async function updateStatus() {
|
|
232
|
+
try {
|
|
233
|
+
const res = await fetch('/api/status');
|
|
234
|
+
const data = await res.json();
|
|
235
|
+
|
|
236
|
+
const badge = document.getElementById('badge-status');
|
|
237
|
+
badge.innerText = data.status || 'unknown';
|
|
238
|
+
badge.className = 'badge badge-' + (data.status || 'connecting');
|
|
239
|
+
|
|
240
|
+
document.getElementById('val-user').innerText = data.user?.id ? data.user.id.split('@')[0] : 'Belum Login';
|
|
241
|
+
document.getElementById('val-ram').innerText = data.memory ? data.memory.processMB + ' MB' : '-';
|
|
242
|
+
|
|
243
|
+
const uptime = data.uptime || 0;
|
|
244
|
+
const mins = Math.floor(uptime / 60);
|
|
245
|
+
const secs = uptime % 60;
|
|
246
|
+
document.getElementById('val-uptime').innerText = mins + 'm ' + secs + 's';
|
|
247
|
+
} catch (e) {}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function updateMessages() {
|
|
251
|
+
try {
|
|
252
|
+
const res = await fetch('/api/messages');
|
|
253
|
+
const list = await res.json();
|
|
254
|
+
const container = document.getElementById('messages-list');
|
|
255
|
+
if (!list || !list.length) return;
|
|
256
|
+
|
|
257
|
+
container.innerHTML = list.map(m => \`
|
|
258
|
+
<div class="msg-item">
|
|
259
|
+
<div class="meta">
|
|
260
|
+
<span>\${m.fromMe ? '🟢 OUT' : '🔵 IN'} • @\${m.sender}</span>
|
|
261
|
+
<span>\${m.time}</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div>\${m.text}</div>
|
|
264
|
+
</div>
|
|
265
|
+
\`).join('');
|
|
266
|
+
} catch (e) {}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function sendMessage() {
|
|
270
|
+
const jid = document.getElementById('input-jid').value.trim();
|
|
271
|
+
const text = document.getElementById('input-text').value.trim();
|
|
272
|
+
const status = document.getElementById('send-status');
|
|
273
|
+
if (!jid || !text) return alert('Isi nomor dan pesan terlebih dahulu!');
|
|
274
|
+
status.innerText = 'Mengirim...';
|
|
275
|
+
try {
|
|
276
|
+
const res = await fetch('/api/send', {
|
|
277
|
+
method: 'POST',
|
|
278
|
+
headers: { 'Content-Type': 'application/json' },
|
|
279
|
+
body: JSON.stringify({ jid, text })
|
|
280
|
+
});
|
|
281
|
+
const data = await res.json();
|
|
282
|
+
if (data.success) {
|
|
283
|
+
status.innerText = '✅ Terkirim! ID: ' + data.id;
|
|
284
|
+
document.getElementById('input-text').value = '';
|
|
285
|
+
} else {
|
|
286
|
+
status.innerText = '❌ Gagal: ' + data.error;
|
|
287
|
+
}
|
|
288
|
+
} catch (err) {
|
|
289
|
+
status.innerText = '❌ Error: ' + err.message;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
setInterval(updateStatus, 2000);
|
|
294
|
+
setInterval(updateMessages, 1500);
|
|
295
|
+
updateStatus();
|
|
296
|
+
updateMessages();
|
|
297
|
+
</script>
|
|
298
|
+
</body>
|
|
299
|
+
</html>`;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { getBinaryNodeChild } from '../WABinary/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Menambahkan peserta ke grup dengan engine bypass pembatasan privasi (Privacy 403 Bypass).
|
|
5
|
+
* Jika peserta menyetel privasi grup ke "Kontak Saya" atau "Tidak Ada" (Error 403),
|
|
6
|
+
* engine otomatis mengambil kode undangan resmi yang ditandatangani server WhatsApp,
|
|
7
|
+
* lalu mengirim kartu undangan GroupInviteMessage (V4) langsung ke chat pribadi target.
|
|
8
|
+
*
|
|
9
|
+
* @param {any} sock Socket Baileys
|
|
10
|
+
* @param {string} groupJid JID grup tujuan
|
|
11
|
+
* @param {string[]|string} participants JID nomor yang ingin ditambahkan
|
|
12
|
+
* @param {object} [options={}] Opsi tambahan
|
|
13
|
+
* @param {boolean} [options.autoInvite=true] Otomatis kirim kartu undangan jika terblokir privasi 403
|
|
14
|
+
* @param {string} [options.caption] Teks pengantar undangan
|
|
15
|
+
* @returns {Promise<Array<{ jid: string, status: string, bypassed: boolean, inviteCode?: string, inviteExpiration?: number }>>}
|
|
16
|
+
*/
|
|
17
|
+
export const groupAddWithBypass = async (sock, groupJid, participants, options = {}) => {
|
|
18
|
+
const list = Array.isArray(participants) ? participants : [participants];
|
|
19
|
+
const autoInvite = options.autoInvite !== false;
|
|
20
|
+
|
|
21
|
+
// 1. Eksekusi penambahan langsung via WhatsApp protocol
|
|
22
|
+
const updateResults = await sock.groupParticipantsUpdate(groupJid, list, 'add');
|
|
23
|
+
const finalResults = [];
|
|
24
|
+
|
|
25
|
+
let groupMeta = null;
|
|
26
|
+
const getMeta = async () => {
|
|
27
|
+
if (!groupMeta) {
|
|
28
|
+
try {
|
|
29
|
+
groupMeta = await sock.groupMetadata(groupJid);
|
|
30
|
+
} catch {
|
|
31
|
+
groupMeta = { subject: 'Grup WhatsApp' };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return groupMeta;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
for (const res of updateResults) {
|
|
38
|
+
if (res.status === '403') {
|
|
39
|
+
// Server WhatsApp menolak add langsung karena privasi target, tapi memberikan add_request token resmi
|
|
40
|
+
const addRequestNode = getBinaryNodeChild(res.content, 'add_request');
|
|
41
|
+
const code = addRequestNode?.attrs?.code;
|
|
42
|
+
const expiration = addRequestNode?.attrs?.expiration;
|
|
43
|
+
|
|
44
|
+
if (code && expiration && autoInvite) {
|
|
45
|
+
try {
|
|
46
|
+
const meta = await getMeta();
|
|
47
|
+
await sock.sendMessage(res.jid, {
|
|
48
|
+
groupInviteMessage: {
|
|
49
|
+
groupJid: groupJid,
|
|
50
|
+
groupName: meta.subject || 'Grup WhatsApp',
|
|
51
|
+
caption: options.caption || `Halo! Kamu diundang bergabung ke grup *${meta.subject || 'Grup'}*. Klik tombol di bawah untuk bergabung langsung.`,
|
|
52
|
+
inviteCode: code,
|
|
53
|
+
inviteExpiration: Number(expiration)
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
finalResults.push({
|
|
58
|
+
jid: res.jid,
|
|
59
|
+
status: '403_bypassed_with_invite',
|
|
60
|
+
bypassed: true,
|
|
61
|
+
inviteCode: code,
|
|
62
|
+
inviteExpiration: Number(expiration)
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
} catch (inviteErr) {
|
|
66
|
+
sock.logger?.warn?.({ err: inviteErr }, 'groupAddWithBypass: Gagal mengirim V4 group invite card');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
finalResults.push({
|
|
71
|
+
jid: res.jid,
|
|
72
|
+
status: '403',
|
|
73
|
+
bypassed: false,
|
|
74
|
+
inviteCode: code,
|
|
75
|
+
inviteExpiration: expiration ? Number(expiration) : undefined
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
finalResults.push({
|
|
79
|
+
jid: res.jid,
|
|
80
|
+
status: res.status || '200',
|
|
81
|
+
bypassed: res.status === '200'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return finalResults;
|
|
87
|
+
};
|
package/src/Lyxe/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import type { proto } from '../WAProto/index.js';
|
|
3
|
+
import type https from 'https';
|
|
3
4
|
|
|
4
5
|
export interface ViewOnceDownloadResult {
|
|
5
6
|
buffer: Buffer;
|
|
@@ -9,11 +10,19 @@ export interface ViewOnceDownloadResult {
|
|
|
9
10
|
fileName: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
export interface GroupBypassResult {
|
|
14
|
+
jid: string;
|
|
15
|
+
status: string;
|
|
16
|
+
bypassed: boolean;
|
|
17
|
+
inviteCode?: string;
|
|
18
|
+
inviteExpiration?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export declare const smartDelay: (minMs?: number, maxMs?: number) => Promise<void>;
|
|
13
22
|
export declare const simulateTyping: (sock: any, jid: string, durationMs?: number) => Promise<void>;
|
|
14
23
|
export declare const simulateRecording: (sock: any, jid: string, durationMs?: number) => Promise<void>;
|
|
15
24
|
|
|
16
|
-
export declare const downloadViewOnce: (message: any) => Promise<ViewOnceDownloadResult>;
|
|
25
|
+
export declare const downloadViewOnce: (message: any, store?: any) => Promise<ViewOnceDownloadResult>;
|
|
17
26
|
export declare const extractRevokedMessage: (store: any, revocationMsg: any) => any | null;
|
|
18
27
|
|
|
19
28
|
export declare const readStatus: (sock: any, statusMessage: any, delayMs?: number) => Promise<any>;
|
|
@@ -27,6 +36,42 @@ export declare const sendVoiceNote: (sock: any, jid: string, audio: Buffer | { u
|
|
|
27
36
|
export declare const sendImageAsSticker: (sock: any, jid: string, sticker: Buffer | { url: string } | string, quoted?: any, options?: any) => Promise<any>;
|
|
28
37
|
export declare const sendHDMedia: (sock: any, jid: string, mediaContent: { image?: any; video?: any; caption?: string }, options?: any) => Promise<any>;
|
|
29
38
|
|
|
39
|
+
export declare const sendVideoNote: (sock: any, jid: string, video: Buffer | { url: string } | string, options?: any) => Promise<any>;
|
|
40
|
+
|
|
41
|
+
export declare const groupAddWithBypass: (sock: any, groupJid: string, participants: string[] | string, options?: { autoInvite?: boolean; caption?: string }) => Promise<GroupBypassResult[]>;
|
|
42
|
+
|
|
43
|
+
export declare const CHROME_TLS_CONFIG: any;
|
|
44
|
+
export declare const CHROME_BROWSER_HEADERS: Record<string, string>;
|
|
45
|
+
export declare const createProxyAgent: (proxy?: string | object, customTlsOptions?: any) => https.Agent;
|
|
46
|
+
|
|
47
|
+
export declare class ImmortalVault {
|
|
48
|
+
constructor(options?: { dir?: string; enabled?: boolean; maxItems?: number });
|
|
49
|
+
recordMessage(msg: any, sock: any): Promise<void>;
|
|
50
|
+
markRevoked(revokedKey: any): any | null;
|
|
51
|
+
search(query: string): any[];
|
|
52
|
+
get(msgId: string): any | null;
|
|
53
|
+
list(limit?: number): any[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export declare class LyxeDashboard {
|
|
57
|
+
constructor(sock: any, options?: { port?: number });
|
|
58
|
+
start(): void;
|
|
59
|
+
stop(): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export declare class TelegramBridge {
|
|
63
|
+
constructor(sock: any, options: { token: string; teleChatId?: string | number; waTargetJid: string; prefixHeader?: string; autoStart?: boolean });
|
|
64
|
+
start(): void;
|
|
65
|
+
stop(): void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export declare class PresenceRadar {
|
|
69
|
+
constructor(sock: any);
|
|
70
|
+
track(jid: string, callback?: (ev: { jid: string; status: 'online' | 'offline'; time: number; durationMs?: number }) => void): Promise<string>;
|
|
71
|
+
getHistory(jid: string): any[];
|
|
72
|
+
getStatus(jid: string): { online: boolean; lastSeen: number } | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
30
75
|
export declare class LyxeSessionManager {
|
|
31
76
|
constructor(options?: { baseConfig?: any; createSocketFn?: any });
|
|
32
77
|
setSocketFactory(fn: (config: any) => any): void;
|
package/src/Lyxe/index.js
CHANGED
|
@@ -4,6 +4,13 @@ import { readStatus, reactStatus, sendStatusMention, sendVoiceStatus } from './s
|
|
|
4
4
|
import { streamMessage } from './ai-stream.js';
|
|
5
5
|
import { sendVoiceNote, sendImageAsSticker, sendHDMedia } from './media-tools.js';
|
|
6
6
|
import { LyxeSessionManager } from './session-manager.js';
|
|
7
|
+
import { groupAddWithBypass } from './group-bypass.js';
|
|
8
|
+
import { createProxyAgent, CHROME_TLS_CONFIG, CHROME_BROWSER_HEADERS } from '../Socket/Client/proxy-agent.js';
|
|
9
|
+
import { ImmortalVault } from './vault.js';
|
|
10
|
+
import { LyxeDashboard } from './dashboard.js';
|
|
11
|
+
import { TelegramBridge } from './telegram-bridge.js';
|
|
12
|
+
import { PresenceRadar } from './radar.js';
|
|
13
|
+
import { sendVideoNote } from './video-note.js';
|
|
7
14
|
|
|
8
15
|
export {
|
|
9
16
|
smartDelay,
|
|
@@ -19,7 +26,16 @@ export {
|
|
|
19
26
|
sendVoiceNote,
|
|
20
27
|
sendImageAsSticker,
|
|
21
28
|
sendHDMedia,
|
|
22
|
-
LyxeSessionManager
|
|
29
|
+
LyxeSessionManager,
|
|
30
|
+
groupAddWithBypass,
|
|
31
|
+
createProxyAgent,
|
|
32
|
+
CHROME_TLS_CONFIG,
|
|
33
|
+
CHROME_BROWSER_HEADERS,
|
|
34
|
+
ImmortalVault,
|
|
35
|
+
LyxeDashboard,
|
|
36
|
+
TelegramBridge,
|
|
37
|
+
PresenceRadar,
|
|
38
|
+
sendVideoNote
|
|
23
39
|
};
|
|
24
40
|
|
|
25
41
|
/**
|
|
@@ -34,7 +50,7 @@ export const bindLyxeHelpers = (sock, config = {}) => {
|
|
|
34
50
|
sock.simulateRecording = (jid, durationMs) => simulateRecording(sock, jid, durationMs);
|
|
35
51
|
|
|
36
52
|
// 2. Anti-Delete & View Once
|
|
37
|
-
sock.downloadViewOnce = (message) => downloadViewOnce(message);
|
|
53
|
+
sock.downloadViewOnce = (message, store) => downloadViewOnce(message, store);
|
|
38
54
|
sock.extractRevokedMessage = (store, revocationMsg) => extractRevokedMessage(store, revocationMsg);
|
|
39
55
|
|
|
40
56
|
// 3. Status / Story Tools
|
|
@@ -51,6 +67,40 @@ export const bindLyxeHelpers = (sock, config = {}) => {
|
|
|
51
67
|
// 5. AI Streaming
|
|
52
68
|
sock.streamMessage = (jid, stream, options) => streamMessage(sock, jid, stream, options);
|
|
53
69
|
|
|
70
|
+
// 6. Group Privacy 403 Bypass Engine
|
|
71
|
+
sock.groupAddWithBypass = (jid, participants, options) => groupAddWithBypass(sock, jid, participants, options);
|
|
72
|
+
|
|
73
|
+
// 7. Video Note Bulat (Telegram-Style PTV)
|
|
74
|
+
sock.sendVideoNote = (jid, video, options) => sendVideoNote(sock, jid, video, options);
|
|
75
|
+
|
|
76
|
+
// 8. Immortal Media & Message Vault
|
|
77
|
+
sock.vault = new ImmortalVault(config.vaultOptions || {});
|
|
78
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
79
|
+
for (const msg of messages || []) {
|
|
80
|
+
sock.vault.recordMessage(msg, sock);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// 9. Intelligence Presence Radar (Stalker Engine)
|
|
85
|
+
sock.radar = new PresenceRadar(sock);
|
|
86
|
+
sock.trackPresence = (jid, callback) => sock.radar.track(jid, callback);
|
|
87
|
+
|
|
88
|
+
// 10. Telegram to WhatsApp Bridge
|
|
89
|
+
sock.bridgeTelegram = (options) => new TelegramBridge(sock, options);
|
|
90
|
+
|
|
91
|
+
// 11. Built-in Web Cockpit Dashboard
|
|
92
|
+
sock.startDashboard = (port = 3000) => {
|
|
93
|
+
if (!sock.dashboard) {
|
|
94
|
+
sock.dashboard = new LyxeDashboard(sock, { port });
|
|
95
|
+
sock.dashboard.start();
|
|
96
|
+
}
|
|
97
|
+
return sock.dashboard;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
if (config.dashboard === true) {
|
|
101
|
+
sock.startDashboard(config.dashboardPort || 3000);
|
|
102
|
+
}
|
|
103
|
+
|
|
54
104
|
// Otomatis inject opsi simulateTyping di sendMessage jika diaktifkan
|
|
55
105
|
const originalSendMessage = sock.sendMessage.bind(sock);
|
|
56
106
|
sock.sendMessage = async (jid, content, options = {}) => {
|