vinzzsync-wacli 1.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/c.js +2 -0
- package/func.js +3263 -0
- package/index.js +2416 -0
- package/index2.js +3611 -0
- package/lib/sqlAuth.js +109 -0
- package/package.json +21 -0
- package/plugins/_loader.js +191 -0
- package/plugins/addplugins.js +93 -0
- package/plugins/backup.js +91 -0
- package/plugins/cekch.js +157 -0
- package/plugins/cekgb.js +105 -0
- package/plugins/clear.js +12 -0
- package/plugins/cmd.js +69 -0
- package/plugins/cmfil.js +110 -0
- package/plugins/cms.js +474 -0
- package/plugins/delplugins.js +57 -0
- package/plugins/dmsg.js +112 -0
- package/plugins/eval.js +175 -0
- package/plugins/evfil.js +86 -0
- package/plugins/exit.js +11 -0
- package/plugins/fadm.js +107 -0
- package/plugins/fakemsg.js +154 -0
- package/plugins/fakesize.js +204 -0
- package/plugins/fclick.js +111 -0
- package/plugins/fitnah.js +87 -0
- package/plugins/getfile.js +169 -0
- package/plugins/getplugins.js +71 -0
- package/plugins/getquoted.js +76 -0
- package/plugins/getusn.js +92 -0
- package/plugins/groups.js +62 -0
- package/plugins/help.js +19 -0
- package/plugins/ht.js +45 -0
- package/plugins/ht2.js +59 -0
- package/plugins/ht3.js +66 -0
- package/plugins/isbot.js +177 -0
- package/plugins/listplugins.js +103 -0
- package/plugins/me.js +95 -0
- package/plugins/minigames.js +144 -0
- package/plugins/ping.js +124 -0
- package/plugins/quoted.js +102 -0
- package/plugins/rvo.js +88 -0
- package/plugins/savefile.js +334 -0
- package/plugins/send.js +52 -0
- package/plugins/session.js +18 -0
- package/plugins/smsg.js +204 -0
- package/plugins/status.js +18 -0
- package/plugins/typing_troll.js +91 -0
- package/pp.jpg +0 -0
- package/vkazee-send-message.js +1238 -0
package/index2.js
ADDED
|
@@ -0,0 +1,3611 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// SMART WA CLI
|
|
3
|
+
// - Auto detect MultiFile / SQLite session
|
|
4
|
+
// - Auto reconnect
|
|
5
|
+
// - Dynamic WA Web version when supported
|
|
6
|
+
// - Incoming message callback/debug
|
|
7
|
+
// - send / eval / cmd / exec / me / profile / status
|
|
8
|
+
// ============================================================
|
|
9
|
+
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import util from 'util';
|
|
13
|
+
import crypto from "crypto";
|
|
14
|
+
import qrcode from 'qrcode-terminal'
|
|
15
|
+
import readline from 'readline';
|
|
16
|
+
import { exec } from 'child_process';
|
|
17
|
+
import prompts from 'prompts';
|
|
18
|
+
import Database from 'better-sqlite3';
|
|
19
|
+
import { VERSION, Button, ButtonV2, Carousel, AIRich, Toolkit } from "./func.js";
|
|
20
|
+
import { pathToFileURL } from 'url';
|
|
21
|
+
|
|
22
|
+
// ------------------------------------------------------------
|
|
23
|
+
// BAILEYS - dynamic import supaya export fork lebih fleksibel
|
|
24
|
+
// ------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
const baileys = await import('@vkazee/baileys');
|
|
27
|
+
|
|
28
|
+
const makeWASocket =
|
|
29
|
+
baileys.default ??
|
|
30
|
+
baileys.makeWASocket;
|
|
31
|
+
|
|
32
|
+
const delay = baileys.delay;
|
|
33
|
+
|
|
34
|
+
const useMultiFileAuthState =
|
|
35
|
+
baileys.useMultiFileAuthState;
|
|
36
|
+
|
|
37
|
+
const makeCacheableSignalKeyStore =
|
|
38
|
+
baileys.makeCacheableSignalKeyStore;
|
|
39
|
+
|
|
40
|
+
const fetchLatestWaWebVersion =
|
|
41
|
+
baileys.fetchLatestWaWebVersion;
|
|
42
|
+
|
|
43
|
+
const Browsers =
|
|
44
|
+
baileys.Browsers;
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
BufferJSON,
|
|
48
|
+
initAuthCreds
|
|
49
|
+
} = baileys;
|
|
50
|
+
|
|
51
|
+
// ------------------------------------------------------------
|
|
52
|
+
// CONFIG
|
|
53
|
+
// ------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
const SESSION_DIR = path.resolve('./session');
|
|
56
|
+
|
|
57
|
+
const LOG_LEVEL =
|
|
58
|
+
process.env.LOG_LEVEL || 'info';
|
|
59
|
+
|
|
60
|
+
const BASE_RECONNECT_DELAY = 3000;
|
|
61
|
+
const MAX_RECONNECT_DELAY = 30000;
|
|
62
|
+
|
|
63
|
+
const ENABLE_DYNAMIC_VERSION = true;
|
|
64
|
+
|
|
65
|
+
// ------------------------------------------------------------
|
|
66
|
+
// GLOBAL STATE
|
|
67
|
+
// ------------------------------------------------------------
|
|
68
|
+
global.owner = "6285185667890";
|
|
69
|
+
global.ownerr = "6285185667890@s.whatsapp.net";
|
|
70
|
+
let loginMethod = null;
|
|
71
|
+
let sock = null;
|
|
72
|
+
|
|
73
|
+
let sessionType = 'unknown';
|
|
74
|
+
let sessionPath = null;
|
|
75
|
+
|
|
76
|
+
let connectionState = 'closed';
|
|
77
|
+
|
|
78
|
+
let reconnectTimer = null;
|
|
79
|
+
let reconnectAttempts = 0;
|
|
80
|
+
|
|
81
|
+
let shuttingDown = false;
|
|
82
|
+
let terminalStarted = false;
|
|
83
|
+
let lastDisconnectInfo = null;
|
|
84
|
+
|
|
85
|
+
let currentWaVersion = null;
|
|
86
|
+
let lastDisconnect = null;
|
|
87
|
+
let lastConnectionUpdate = null;
|
|
88
|
+
|
|
89
|
+
let messageCount = 0;
|
|
90
|
+
|
|
91
|
+
// ============================================================
|
|
92
|
+
// MESSAGE CACHE
|
|
93
|
+
// ============================================================
|
|
94
|
+
|
|
95
|
+
function getMessageType(message) {
|
|
96
|
+
if (!message) {
|
|
97
|
+
return 'unknown';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const keys =
|
|
101
|
+
Object.keys(
|
|
102
|
+
message
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
keys[0] ||
|
|
107
|
+
'unknown'
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
const messageStore = new Map();
|
|
113
|
+
const MAX_MESSAGES = 2000;
|
|
114
|
+
|
|
115
|
+
function saveMessage(message) {
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
!message?.key?.id ||
|
|
119
|
+
!message?.key?.remoteJid
|
|
120
|
+
) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const key =
|
|
125
|
+
`${message.key.remoteJid}:${message.key.id}`;
|
|
126
|
+
|
|
127
|
+
messageStore.set(
|
|
128
|
+
key,
|
|
129
|
+
message
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Hapus pesan paling lama jika cache penuh
|
|
133
|
+
if (
|
|
134
|
+
messageStore.size >
|
|
135
|
+
MAX_MESSAGES
|
|
136
|
+
) {
|
|
137
|
+
const oldestKey =
|
|
138
|
+
messageStore
|
|
139
|
+
.keys()
|
|
140
|
+
.next()
|
|
141
|
+
.value;
|
|
142
|
+
|
|
143
|
+
messageStore.delete(
|
|
144
|
+
oldestKey
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
async function chooseLoginMethod() {
|
|
151
|
+
const response = await prompts({
|
|
152
|
+
type: 'select',
|
|
153
|
+
name: 'method',
|
|
154
|
+
message: 'Pilih method login:',
|
|
155
|
+
choices: [
|
|
156
|
+
{
|
|
157
|
+
title: 'Scan QR Code',
|
|
158
|
+
value: 'qr'
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
title: 'Pairing Code',
|
|
162
|
+
value: 'pairing'
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
initial: 0
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (!response.method) {
|
|
169
|
+
console.log('\nOperasi dibatalkan.');
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return response.method;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ------------------------------------------------------------
|
|
177
|
+
// READLINE
|
|
178
|
+
// ------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
let rl = null;
|
|
181
|
+
|
|
182
|
+
function initReadline() {
|
|
183
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
184
|
+
process.stdin.setRawMode(false);
|
|
185
|
+
process.stdin.resume();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (rl) {
|
|
189
|
+
try { rl.close(); } catch {}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
rl = readline.createInterface({
|
|
193
|
+
input: process.stdin,
|
|
194
|
+
output: process.stdout,
|
|
195
|
+
terminal: true
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
rl.setPrompt('\x1b[32mroot@wa-cli\x1b[0m:\x1b[34m~\x1b[0m$ ');
|
|
199
|
+
|
|
200
|
+
rl.on('line', async input => {
|
|
201
|
+
if (shuttingDown || (loginMethod === 'pairing' && connectionState !== 'open')) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
await handleCommand(input);
|
|
207
|
+
} catch (err) {
|
|
208
|
+
console.error(err);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!shuttingDown && connectionState === 'open') {
|
|
212
|
+
rl.prompt();
|
|
213
|
+
} else {
|
|
214
|
+
terminalStarted = false;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
// ------------------------------------------------------------
|
|
221
|
+
// COLORS / LOGGING
|
|
222
|
+
// ------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
function now() {
|
|
225
|
+
return new Date().toISOString();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function debug(label, value = '') {
|
|
229
|
+
const prefix =
|
|
230
|
+
`\x1b[36m[${now()}] [DEBUG] ${label}\x1b[0m`;
|
|
231
|
+
|
|
232
|
+
if (
|
|
233
|
+
typeof value === 'object' &&
|
|
234
|
+
value !== null
|
|
235
|
+
) {
|
|
236
|
+
console.log(
|
|
237
|
+
prefix,
|
|
238
|
+
util.inspect(value, {
|
|
239
|
+
depth: 10,
|
|
240
|
+
colors: true,
|
|
241
|
+
compact: false
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
} else {
|
|
245
|
+
console.log(prefix, value);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function info(message) {
|
|
250
|
+
console.log(
|
|
251
|
+
`\x1b[32m[+] ${message}\x1b[0m`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function warn(message) {
|
|
256
|
+
console.log(
|
|
257
|
+
`\x1b[33m[!] ${message}\x1b[0m`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function errlog(message, error = null) {
|
|
262
|
+
console.log(
|
|
263
|
+
`\x1b[31m[ERROR] ${message}\x1b[0m`
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if (error) {
|
|
267
|
+
console.error(
|
|
268
|
+
util.inspect(error, {
|
|
269
|
+
depth: 10,
|
|
270
|
+
colors: true,
|
|
271
|
+
compact: false
|
|
272
|
+
})
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ------------------------------------------------------------
|
|
278
|
+
// SESSION DETECTION
|
|
279
|
+
// ------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
function fileExists(file) {
|
|
282
|
+
try {
|
|
283
|
+
return fs.existsSync(file);
|
|
284
|
+
} catch {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isDirectory(dir) {
|
|
290
|
+
try {
|
|
291
|
+
return fs.statSync(dir).isDirectory();
|
|
292
|
+
} catch {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function detectSQLiteAuth(dbPath) {
|
|
298
|
+
let db;
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
db = new Database(
|
|
302
|
+
dbPath,
|
|
303
|
+
{
|
|
304
|
+
readonly: true,
|
|
305
|
+
fileMustExist: true
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const rows =
|
|
310
|
+
db.prepare(`
|
|
311
|
+
SELECT name
|
|
312
|
+
FROM sqlite_master
|
|
313
|
+
WHERE type = 'table'
|
|
314
|
+
`).all();
|
|
315
|
+
|
|
316
|
+
const tables =
|
|
317
|
+
rows.map(x => x.name);
|
|
318
|
+
|
|
319
|
+
const hasBaileysState =
|
|
320
|
+
tables.includes('baileys_state');
|
|
321
|
+
|
|
322
|
+
let registered = false;
|
|
323
|
+
|
|
324
|
+
if (hasBaileysState) {
|
|
325
|
+
const row =
|
|
326
|
+
db.prepare(`
|
|
327
|
+
SELECT value
|
|
328
|
+
FROM baileys_state
|
|
329
|
+
WHERE key = 'creds'
|
|
330
|
+
LIMIT 1
|
|
331
|
+
`).get();
|
|
332
|
+
|
|
333
|
+
if (row?.value) {
|
|
334
|
+
try {
|
|
335
|
+
const creds =
|
|
336
|
+
JSON.parse(
|
|
337
|
+
Buffer.from(
|
|
338
|
+
row.value
|
|
339
|
+
).toString(),
|
|
340
|
+
BufferJSON?.reviver
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
registered =
|
|
344
|
+
creds?.registered === true;
|
|
345
|
+
} catch {
|
|
346
|
+
registered = false;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
valid: hasBaileysState,
|
|
353
|
+
registered,
|
|
354
|
+
tables
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
} catch (error) {
|
|
358
|
+
debug(
|
|
359
|
+
`SQLite check gagal: ${dbPath}`,
|
|
360
|
+
error.message
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
valid: false,
|
|
365
|
+
registered: false,
|
|
366
|
+
tables: []
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
} finally {
|
|
370
|
+
try {
|
|
371
|
+
db?.close();
|
|
372
|
+
} catch {}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function detectMultiFileAuth(dir) {
|
|
377
|
+
if (!isDirectory(dir)) {
|
|
378
|
+
return {
|
|
379
|
+
valid: false,
|
|
380
|
+
registered: false,
|
|
381
|
+
files: []
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const files =
|
|
386
|
+
fs.readdirSync(dir);
|
|
387
|
+
|
|
388
|
+
const credsPath =
|
|
389
|
+
path.join(dir, 'creds.json');
|
|
390
|
+
|
|
391
|
+
if (!fileExists(credsPath)) {
|
|
392
|
+
return {
|
|
393
|
+
valid: false,
|
|
394
|
+
registered: false,
|
|
395
|
+
files
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
const creds =
|
|
401
|
+
JSON.parse(
|
|
402
|
+
fs.readFileSync(
|
|
403
|
+
credsPath,
|
|
404
|
+
'utf8'
|
|
405
|
+
)
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
valid: true,
|
|
410
|
+
registered:
|
|
411
|
+
creds?.registered === true,
|
|
412
|
+
files
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
} catch {
|
|
416
|
+
return {
|
|
417
|
+
valid: false,
|
|
418
|
+
registered: false,
|
|
419
|
+
files
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Ubah signature fungsi menjadi menerima parameter dir
|
|
425
|
+
function detectSession(targetDir = SESSION_DIR) {
|
|
426
|
+
const result = {
|
|
427
|
+
type: 'none',
|
|
428
|
+
path: null,
|
|
429
|
+
registered: false,
|
|
430
|
+
details: {}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
if (!isDirectory(targetDir)) {
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const entries = fs.readdirSync(targetDir, { withFileTypes: true });
|
|
438
|
+
|
|
439
|
+
const sqliteCandidates = entries
|
|
440
|
+
.filter(entry => entry.isFile() && (entry.name.endsWith('.db') || entry.name.endsWith('.sqlite') || entry.name.endsWith('.sqlite3')))
|
|
441
|
+
.map(entry => path.join(targetDir, entry.name));
|
|
442
|
+
|
|
443
|
+
const sqliteResults = sqliteCandidates.map(dbPath => ({
|
|
444
|
+
dbPath,
|
|
445
|
+
...detectSQLiteAuth(dbPath)
|
|
446
|
+
}));
|
|
447
|
+
|
|
448
|
+
const registeredSQLite = sqliteResults.find(x => x.valid && x.registered);
|
|
449
|
+
if (registeredSQLite) {
|
|
450
|
+
return { type: 'sqlite', path: registeredSQLite.dbPath, registered: true, details: registeredSQLite };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const validSQLite = sqliteResults.find(x => x.valid);
|
|
454
|
+
if (validSQLite) {
|
|
455
|
+
return { type: 'sqlite', path: validSQLite.dbPath, registered: validSQLite.registered, details: validSQLite };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const multi = detectMultiFileAuth(targetDir);
|
|
459
|
+
if (multi.valid) {
|
|
460
|
+
return { type: 'multifile', path: targetDir, registered: multi.registered, details: multi };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
// ------------------------------------------------------------
|
|
468
|
+
// SQLITE AUTH LOADER
|
|
469
|
+
// Kompatibel dengan struktur:
|
|
470
|
+
// baileys_state(key TEXT PRIMARY KEY, value BLOB)
|
|
471
|
+
// ------------------------------------------------------------
|
|
472
|
+
|
|
473
|
+
async function useSQLiteAuthState(dbPath) {
|
|
474
|
+
const db =
|
|
475
|
+
new Database(dbPath);
|
|
476
|
+
|
|
477
|
+
db.pragma('journal_mode = WAL');
|
|
478
|
+
|
|
479
|
+
db.prepare(`
|
|
480
|
+
CREATE TABLE IF NOT EXISTS baileys_state (
|
|
481
|
+
key TEXT PRIMARY KEY,
|
|
482
|
+
value BLOB
|
|
483
|
+
)
|
|
484
|
+
`).run();
|
|
485
|
+
|
|
486
|
+
function load(key) {
|
|
487
|
+
const row =
|
|
488
|
+
db.prepare(`
|
|
489
|
+
SELECT value
|
|
490
|
+
FROM baileys_state
|
|
491
|
+
WHERE key = ?
|
|
492
|
+
LIMIT 1
|
|
493
|
+
`).get(key);
|
|
494
|
+
|
|
495
|
+
if (!row) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
return JSON.parse(
|
|
501
|
+
Buffer.from(
|
|
502
|
+
row.value
|
|
503
|
+
).toString(),
|
|
504
|
+
BufferJSON?.reviver
|
|
505
|
+
);
|
|
506
|
+
} catch {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function save(key, data) {
|
|
512
|
+
const json =
|
|
513
|
+
JSON.stringify(
|
|
514
|
+
data,
|
|
515
|
+
BufferJSON?.replacer
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
const buffer =
|
|
519
|
+
Buffer.from(
|
|
520
|
+
json,
|
|
521
|
+
'utf8'
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
db.prepare(`
|
|
525
|
+
INSERT OR REPLACE INTO baileys_state
|
|
526
|
+
(key, value)
|
|
527
|
+
VALUES (?, ?)
|
|
528
|
+
`).run(
|
|
529
|
+
key,
|
|
530
|
+
buffer
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function remove(key) {
|
|
535
|
+
db.prepare(`
|
|
536
|
+
DELETE FROM baileys_state
|
|
537
|
+
WHERE key = ?
|
|
538
|
+
`).run(key);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const creds =
|
|
542
|
+
load('creds') ||
|
|
543
|
+
initAuthCreds();
|
|
544
|
+
|
|
545
|
+
const keys = {};
|
|
546
|
+
|
|
547
|
+
const categories = [
|
|
548
|
+
'pre-key',
|
|
549
|
+
'session',
|
|
550
|
+
'sender-key',
|
|
551
|
+
'app-state-sync-key',
|
|
552
|
+
'app-state-sync-version',
|
|
553
|
+
'lid-mapping',
|
|
554
|
+
'device-list'
|
|
555
|
+
];
|
|
556
|
+
|
|
557
|
+
for (
|
|
558
|
+
const category of categories
|
|
559
|
+
) {
|
|
560
|
+
keys[category] = {};
|
|
561
|
+
|
|
562
|
+
const rows =
|
|
563
|
+
db.prepare(`
|
|
564
|
+
SELECT key, value
|
|
565
|
+
FROM baileys_state
|
|
566
|
+
WHERE key LIKE ?
|
|
567
|
+
`).all(
|
|
568
|
+
`${category}:%`
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
for (
|
|
572
|
+
const row of rows
|
|
573
|
+
) {
|
|
574
|
+
try {
|
|
575
|
+
const id =
|
|
576
|
+
row.key.slice(
|
|
577
|
+
category.length + 1
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
keys[category][id] =
|
|
581
|
+
JSON.parse(
|
|
582
|
+
Buffer.from(
|
|
583
|
+
row.value
|
|
584
|
+
).toString(),
|
|
585
|
+
BufferJSON?.reviver
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
} catch {
|
|
589
|
+
// skip corrupt row
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const state = {
|
|
595
|
+
creds,
|
|
596
|
+
|
|
597
|
+
keys: {
|
|
598
|
+
|
|
599
|
+
get: async (
|
|
600
|
+
type,
|
|
601
|
+
ids
|
|
602
|
+
) => {
|
|
603
|
+
|
|
604
|
+
const data = {};
|
|
605
|
+
|
|
606
|
+
for (
|
|
607
|
+
const id of ids
|
|
608
|
+
) {
|
|
609
|
+
const value =
|
|
610
|
+
load(
|
|
611
|
+
`${type}:${id}`
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
if (
|
|
615
|
+
value !== null &&
|
|
616
|
+
value !== undefined
|
|
617
|
+
) {
|
|
618
|
+
data[id] = value;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return data;
|
|
623
|
+
},
|
|
624
|
+
|
|
625
|
+
set: async (
|
|
626
|
+
data
|
|
627
|
+
) => {
|
|
628
|
+
|
|
629
|
+
for (
|
|
630
|
+
const category
|
|
631
|
+
in data
|
|
632
|
+
) {
|
|
633
|
+
|
|
634
|
+
for (
|
|
635
|
+
const id
|
|
636
|
+
in data[category]
|
|
637
|
+
) {
|
|
638
|
+
|
|
639
|
+
const value =
|
|
640
|
+
data[
|
|
641
|
+
category
|
|
642
|
+
][id];
|
|
643
|
+
|
|
644
|
+
save(
|
|
645
|
+
`${category}:${id}`,
|
|
646
|
+
value
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
async function saveCreds() {
|
|
655
|
+
save(
|
|
656
|
+
'creds',
|
|
657
|
+
creds
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Persist berkala
|
|
662
|
+
const interval =
|
|
663
|
+
setInterval(
|
|
664
|
+
() => {
|
|
665
|
+
try {
|
|
666
|
+
save(
|
|
667
|
+
'creds',
|
|
668
|
+
creds
|
|
669
|
+
);
|
|
670
|
+
} catch {}
|
|
671
|
+
},
|
|
672
|
+
30000
|
|
673
|
+
);
|
|
674
|
+
|
|
675
|
+
interval.unref?.();
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
state,
|
|
679
|
+
saveCreds,
|
|
680
|
+
close: () => {
|
|
681
|
+
try {
|
|
682
|
+
clearInterval(
|
|
683
|
+
interval
|
|
684
|
+
);
|
|
685
|
+
} catch {}
|
|
686
|
+
|
|
687
|
+
try {
|
|
688
|
+
db.close();
|
|
689
|
+
} catch {}
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
// util internal
|
|
693
|
+
_db: db,
|
|
694
|
+
_remove: remove
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// ------------------------------------------------------------
|
|
699
|
+
// WEB VERSION
|
|
700
|
+
// ------------------------------------------------------------
|
|
701
|
+
|
|
702
|
+
async function getLatestVersion() {
|
|
703
|
+
if (
|
|
704
|
+
!ENABLE_DYNAMIC_VERSION ||
|
|
705
|
+
typeof fetchLatestWaWebVersion !==
|
|
706
|
+
'function'
|
|
707
|
+
) {
|
|
708
|
+
debug(
|
|
709
|
+
'fetchLatestWaWebVersion tidak tersedia'
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
try {
|
|
716
|
+
const result =
|
|
717
|
+
await fetchLatestWaWebVersion();
|
|
718
|
+
|
|
719
|
+
debug(
|
|
720
|
+
'WA Web version result',
|
|
721
|
+
result
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
if (
|
|
725
|
+
result?.version &&
|
|
726
|
+
Array.isArray(
|
|
727
|
+
result.version
|
|
728
|
+
)
|
|
729
|
+
) {
|
|
730
|
+
|
|
731
|
+
currentWaVersion =
|
|
732
|
+
result.version;
|
|
733
|
+
|
|
734
|
+
info(
|
|
735
|
+
`WA Web version: ${
|
|
736
|
+
result.version.join('.')
|
|
737
|
+
}`
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
return result.version;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
} catch (error) {
|
|
744
|
+
warn(
|
|
745
|
+
`Gagal mengambil WA Web version: ${
|
|
746
|
+
error.message
|
|
747
|
+
}`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// ------------------------------------------------------------
|
|
755
|
+
// QR OPTIONAL RENDER
|
|
756
|
+
// Tidak wajib install qrcode-terminal.
|
|
757
|
+
// ------------------------------------------------------------
|
|
758
|
+
|
|
759
|
+
async function renderQR(qr) {
|
|
760
|
+
try {
|
|
761
|
+
const mod =
|
|
762
|
+
await import(
|
|
763
|
+
'qrcode-terminal'
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
const qrTerminal =
|
|
767
|
+
mod.default ??
|
|
768
|
+
mod;
|
|
769
|
+
|
|
770
|
+
if (
|
|
771
|
+
typeof qrTerminal.generate ===
|
|
772
|
+
'function'
|
|
773
|
+
) {
|
|
774
|
+
qrTerminal.generate(
|
|
775
|
+
qr,
|
|
776
|
+
{
|
|
777
|
+
small: true
|
|
778
|
+
}
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
} catch {
|
|
785
|
+
// package tidak terpasang
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
console.log('');
|
|
789
|
+
console.log(
|
|
790
|
+
'[QR] qrcode-terminal tidak terpasang.'
|
|
791
|
+
);
|
|
792
|
+
console.log(
|
|
793
|
+
'[QR] QR tersedia pada event connection.update.'
|
|
794
|
+
);
|
|
795
|
+
console.log('');
|
|
796
|
+
|
|
797
|
+
return false;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// ------------------------------------------------------------
|
|
801
|
+
// MESSAGE TEXT EXTRACTION
|
|
802
|
+
// ------------------------------------------------------------
|
|
803
|
+
|
|
804
|
+
function extractMessageText(message) {
|
|
805
|
+
if (!message) {
|
|
806
|
+
return '';
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return (
|
|
810
|
+
message.conversation ||
|
|
811
|
+
|
|
812
|
+
message.extendedTextMessage
|
|
813
|
+
?.text ||
|
|
814
|
+
|
|
815
|
+
message.imageMessage
|
|
816
|
+
?.caption ||
|
|
817
|
+
|
|
818
|
+
message.videoMessage
|
|
819
|
+
?.caption ||
|
|
820
|
+
|
|
821
|
+
message.documentMessage
|
|
822
|
+
?.caption ||
|
|
823
|
+
|
|
824
|
+
message.buttonsResponseMessage
|
|
825
|
+
?.selectedDisplayText ||
|
|
826
|
+
|
|
827
|
+
message.listResponseMessage
|
|
828
|
+
?.title ||
|
|
829
|
+
|
|
830
|
+
message.templateButtonReplyMessage
|
|
831
|
+
?.selectedDisplayText ||
|
|
832
|
+
|
|
833
|
+
message.interactiveResponseMessage
|
|
834
|
+
?.body
|
|
835
|
+
?.text ||
|
|
836
|
+
|
|
837
|
+
''
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function setupCLIInput() {
|
|
842
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
843
|
+
process.stdin.setRawMode(false);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (rl) rl.close();
|
|
847
|
+
|
|
848
|
+
rl = readline.createInterface({
|
|
849
|
+
input: process.stdin,
|
|
850
|
+
output: process.stdout,
|
|
851
|
+
terminal: true
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// SET PROMPT CUSTOM DENGAN WARNA HIJAU ANSI (\x1b[32m)
|
|
855
|
+
const greenPrompt = '\x1b[32mroot@bot-wa:~$\x1b[0m ';
|
|
856
|
+
rl.setPrompt(greenPrompt);
|
|
857
|
+
|
|
858
|
+
rl.on('line', async (line) => {
|
|
859
|
+
const input = line.trim();
|
|
860
|
+
if (input) {
|
|
861
|
+
await handleCommand(input);
|
|
862
|
+
}
|
|
863
|
+
// Munculkan lagi prompt hijau setelah command selesai dieksekusi
|
|
864
|
+
rl.prompt();
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
// Tampilkan prompt untuk pertama kali
|
|
868
|
+
rl.prompt();
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
// ------------------------------------------------------------
|
|
873
|
+
// JID HELPER
|
|
874
|
+
// ------------------------------------------------------------
|
|
875
|
+
|
|
876
|
+
function normalizeJid(input) {
|
|
877
|
+
if (!input) {
|
|
878
|
+
return null;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (
|
|
882
|
+
input.includes('@')
|
|
883
|
+
) {
|
|
884
|
+
return input;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
const clean =
|
|
888
|
+
input
|
|
889
|
+
.replace(
|
|
890
|
+
/[^\d]/g,
|
|
891
|
+
''
|
|
892
|
+
);
|
|
893
|
+
|
|
894
|
+
if (!clean) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
return (
|
|
899
|
+
`${clean}@s.whatsapp.net`
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// ------------------------------------------------------------
|
|
904
|
+
// DISCONNECT
|
|
905
|
+
// ------------------------------------------------------------
|
|
906
|
+
|
|
907
|
+
function parseDisconnect(
|
|
908
|
+
lastDisconnect
|
|
909
|
+
) {
|
|
910
|
+
|
|
911
|
+
const error =
|
|
912
|
+
lastDisconnect?.error;
|
|
913
|
+
|
|
914
|
+
return {
|
|
915
|
+
message:
|
|
916
|
+
error?.message ||
|
|
917
|
+
'Unknown error',
|
|
918
|
+
|
|
919
|
+
statusCode:
|
|
920
|
+
error?.output?.statusCode ??
|
|
921
|
+
error?.statusCode ??
|
|
922
|
+
error?.data?.statusCode ??
|
|
923
|
+
null,
|
|
924
|
+
|
|
925
|
+
reason:
|
|
926
|
+
error?.data?.reason ??
|
|
927
|
+
null,
|
|
928
|
+
|
|
929
|
+
location:
|
|
930
|
+
error?.data?.location ??
|
|
931
|
+
null,
|
|
932
|
+
|
|
933
|
+
name:
|
|
934
|
+
error?.name ??
|
|
935
|
+
null,
|
|
936
|
+
|
|
937
|
+
stack:
|
|
938
|
+
error?.stack ??
|
|
939
|
+
null
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// ------------------------------------------------------------
|
|
944
|
+
// RECONNECT
|
|
945
|
+
// ------------------------------------------------------------
|
|
946
|
+
|
|
947
|
+
function reconnectDelay() {
|
|
948
|
+
const delay =
|
|
949
|
+
BASE_RECONNECT_DELAY *
|
|
950
|
+
Math.pow(
|
|
951
|
+
2,
|
|
952
|
+
Math.min(
|
|
953
|
+
reconnectAttempts,
|
|
954
|
+
4
|
|
955
|
+
)
|
|
956
|
+
);
|
|
957
|
+
|
|
958
|
+
return Math.min(
|
|
959
|
+
delay,
|
|
960
|
+
MAX_RECONNECT_DELAY
|
|
961
|
+
);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function scheduleReconnect() {
|
|
965
|
+
if (
|
|
966
|
+
shuttingDown
|
|
967
|
+
) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if (
|
|
972
|
+
reconnectTimer
|
|
973
|
+
) {
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
reconnectAttempts++;
|
|
978
|
+
|
|
979
|
+
const delay =
|
|
980
|
+
reconnectDelay();
|
|
981
|
+
|
|
982
|
+
warn(
|
|
983
|
+
`Reconnect #${reconnectAttempts} dalam ${delay} ms`
|
|
984
|
+
);
|
|
985
|
+
|
|
986
|
+
reconnectTimer =
|
|
987
|
+
setTimeout(
|
|
988
|
+
async () => {
|
|
989
|
+
|
|
990
|
+
reconnectTimer =
|
|
991
|
+
null;
|
|
992
|
+
|
|
993
|
+
try {
|
|
994
|
+
await connectWhatsApp(ACTIVE_SESSION_DIR);
|
|
995
|
+
} catch (error) {
|
|
996
|
+
errlog(
|
|
997
|
+
'Reconnect error',
|
|
998
|
+
error
|
|
999
|
+
);
|
|
1000
|
+
|
|
1001
|
+
scheduleReconnect();
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
delay
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// ------------------------------------------------------------
|
|
1009
|
+
// TERMINAL PROMPT
|
|
1010
|
+
// ------------------------------------------------------------
|
|
1011
|
+
|
|
1012
|
+
function prompt() {
|
|
1013
|
+
if (terminalStarted || shuttingDown) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (connectionState !== 'open') {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
terminalStarted = true;
|
|
1022
|
+
|
|
1023
|
+
console.log('');
|
|
1024
|
+
console.log('Ketik "help" untuk daftar command.');
|
|
1025
|
+
console.log('');
|
|
1026
|
+
|
|
1027
|
+
ask();
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
function ask() {
|
|
1031
|
+
if (shuttingDown || connectionState !== 'open' || !rl) {
|
|
1032
|
+
terminalStarted = false;
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
rl.prompt();
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
/* rl.on('line', async input => {
|
|
1041
|
+
if (
|
|
1042
|
+
shuttingDown ||
|
|
1043
|
+
loginMethod === 'pairing' &&
|
|
1044
|
+
connectionState !== 'open'
|
|
1045
|
+
) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
try {
|
|
1050
|
+
await handleCommand(input);
|
|
1051
|
+
} catch (err) {
|
|
1052
|
+
console.error(err);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
if (
|
|
1056
|
+
!shuttingDown &&
|
|
1057
|
+
connectionState === 'open'
|
|
1058
|
+
) {
|
|
1059
|
+
rl.prompt();
|
|
1060
|
+
} else {
|
|
1061
|
+
terminalStarted = false;
|
|
1062
|
+
}
|
|
1063
|
+
}); */
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
// ------------------------------------------------------------
|
|
1067
|
+
// COMMANDS
|
|
1068
|
+
// ------------------------------------------------------------
|
|
1069
|
+
|
|
1070
|
+
async function handleCommand(
|
|
1071
|
+
input
|
|
1072
|
+
) {
|
|
1073
|
+
|
|
1074
|
+
const trimmed =
|
|
1075
|
+
input.trim();
|
|
1076
|
+
|
|
1077
|
+
if (!trimmed) {
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const args =
|
|
1082
|
+
trimmed.split(
|
|
1083
|
+
/\s+/g
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
const command =
|
|
1087
|
+
args.shift()
|
|
1088
|
+
?.toLowerCase();
|
|
1089
|
+
|
|
1090
|
+
const text =
|
|
1091
|
+
args.join(' ');
|
|
1092
|
+
|
|
1093
|
+
try {
|
|
1094
|
+
|
|
1095
|
+
switch (command) {
|
|
1096
|
+
|
|
1097
|
+
// ================================================
|
|
1098
|
+
// HELP (REALTIME AUTOMATIC)
|
|
1099
|
+
// ================================================
|
|
1100
|
+
|
|
1101
|
+
case 'help': {
|
|
1102
|
+
const commandsList = getDynamicHelpList();
|
|
1103
|
+
|
|
1104
|
+
console.log('\n\x1b[36m================ COMMAND LIST (REALTIME) ================\x1b[0m\n');
|
|
1105
|
+
|
|
1106
|
+
if (commandsList.length > 0) {
|
|
1107
|
+
// Tampilkan per 3-4 kolom agar rapi di terminal
|
|
1108
|
+
let formatted = '';
|
|
1109
|
+
commandsList.forEach((cmd, idx) => {
|
|
1110
|
+
formatted += ` • ${cmd.padEnd(12)}`;
|
|
1111
|
+
if ((idx + 1) % 3 === 0) formatted += '\n';
|
|
1112
|
+
});
|
|
1113
|
+
console.log(formatted);
|
|
1114
|
+
} else {
|
|
1115
|
+
console.log(' Gagal membaca daftar command.');
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
console.log('\n\x1b[36m=========================================================\x1b[0m\n');
|
|
1119
|
+
break;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
// ================================================
|
|
1125
|
+
// SEND
|
|
1126
|
+
// ================================================
|
|
1127
|
+
|
|
1128
|
+
case 'send': {
|
|
1129
|
+
|
|
1130
|
+
if (
|
|
1131
|
+
args.length <
|
|
1132
|
+
2
|
|
1133
|
+
) {
|
|
1134
|
+
console.log(
|
|
1135
|
+
'Gunakan: send <nomor> <pesan>'
|
|
1136
|
+
);
|
|
1137
|
+
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
const target =
|
|
1142
|
+
normalizeJid(
|
|
1143
|
+
args.shift()
|
|
1144
|
+
);
|
|
1145
|
+
|
|
1146
|
+
const message =
|
|
1147
|
+
args.join(' ');
|
|
1148
|
+
|
|
1149
|
+
if (!target) {
|
|
1150
|
+
warn(
|
|
1151
|
+
'Nomor/JID tidak valid.'
|
|
1152
|
+
);
|
|
1153
|
+
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
debug(
|
|
1158
|
+
'sendMessage',
|
|
1159
|
+
{
|
|
1160
|
+
target,
|
|
1161
|
+
message
|
|
1162
|
+
}
|
|
1163
|
+
);
|
|
1164
|
+
|
|
1165
|
+
await sock.sendMessage(
|
|
1166
|
+
target,
|
|
1167
|
+
{
|
|
1168
|
+
text: message
|
|
1169
|
+
}
|
|
1170
|
+
);
|
|
1171
|
+
|
|
1172
|
+
info(
|
|
1173
|
+
`Pesan terkirim ke ${target}`
|
|
1174
|
+
);
|
|
1175
|
+
|
|
1176
|
+
break;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// ================================================
|
|
1180
|
+
// ME / PROFILE
|
|
1181
|
+
// ================================================
|
|
1182
|
+
|
|
1183
|
+
case 'me':
|
|
1184
|
+
case 'profile': {
|
|
1185
|
+
|
|
1186
|
+
console.log('');
|
|
1187
|
+
console.log(
|
|
1188
|
+
'\x1b[36m========== BOT PROFILE ==========\x1b[0m'
|
|
1189
|
+
);
|
|
1190
|
+
|
|
1191
|
+
debug(
|
|
1192
|
+
'sock.user',
|
|
1193
|
+
sock?.user
|
|
1194
|
+
);
|
|
1195
|
+
|
|
1196
|
+
console.log(
|
|
1197
|
+
`ID : ${
|
|
1198
|
+
sock?.user?.id ??
|
|
1199
|
+
'-'
|
|
1200
|
+
}`
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
console.log(
|
|
1204
|
+
`Name : ${
|
|
1205
|
+
sock?.user?.name ??
|
|
1206
|
+
'-'
|
|
1207
|
+
}`
|
|
1208
|
+
);
|
|
1209
|
+
|
|
1210
|
+
console.log(
|
|
1211
|
+
`Verified: ${
|
|
1212
|
+
sock?.user?.verifiedName ??
|
|
1213
|
+
'-'
|
|
1214
|
+
}`
|
|
1215
|
+
);
|
|
1216
|
+
|
|
1217
|
+
console.log(
|
|
1218
|
+
`Status : ${
|
|
1219
|
+
connectionState
|
|
1220
|
+
}`
|
|
1221
|
+
);
|
|
1222
|
+
|
|
1223
|
+
console.log(
|
|
1224
|
+
`Session : ${
|
|
1225
|
+
sessionType
|
|
1226
|
+
}`
|
|
1227
|
+
);
|
|
1228
|
+
|
|
1229
|
+
console.log(
|
|
1230
|
+
'\x1b[36m=================================\x1b[0m'
|
|
1231
|
+
);
|
|
1232
|
+
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// ================================================
|
|
1237
|
+
// STATUS
|
|
1238
|
+
// ================================================
|
|
1239
|
+
|
|
1240
|
+
case 'status': {
|
|
1241
|
+
|
|
1242
|
+
const memory =
|
|
1243
|
+
process.memoryUsage();
|
|
1244
|
+
|
|
1245
|
+
console.log('');
|
|
1246
|
+
console.log(
|
|
1247
|
+
'\x1b[36m========== STATUS ==========\x1b[0m'
|
|
1248
|
+
);
|
|
1249
|
+
|
|
1250
|
+
console.log(
|
|
1251
|
+
`Node : ${process.version}`
|
|
1252
|
+
);
|
|
1253
|
+
|
|
1254
|
+
console.log(
|
|
1255
|
+
`Platform : ${process.platform}`
|
|
1256
|
+
);
|
|
1257
|
+
|
|
1258
|
+
console.log(
|
|
1259
|
+
`Architecture: ${process.arch}`
|
|
1260
|
+
);
|
|
1261
|
+
|
|
1262
|
+
console.log(
|
|
1263
|
+
`PID : ${process.pid}`
|
|
1264
|
+
);
|
|
1265
|
+
|
|
1266
|
+
console.log(
|
|
1267
|
+
`Connection : ${connectionState}`
|
|
1268
|
+
);
|
|
1269
|
+
|
|
1270
|
+
console.log(
|
|
1271
|
+
`Session : ${sessionType}`
|
|
1272
|
+
);
|
|
1273
|
+
|
|
1274
|
+
console.log(
|
|
1275
|
+
`Session path: ${sessionPath ?? '-'}`
|
|
1276
|
+
);
|
|
1277
|
+
|
|
1278
|
+
console.log(
|
|
1279
|
+
`Reconnect : ${reconnectAttempts}`
|
|
1280
|
+
);
|
|
1281
|
+
|
|
1282
|
+
console.log(
|
|
1283
|
+
`Messages : ${messageCount}`
|
|
1284
|
+
);
|
|
1285
|
+
|
|
1286
|
+
console.log(
|
|
1287
|
+
`WA version : ${
|
|
1288
|
+
currentWaVersion
|
|
1289
|
+
? currentWaVersion.join('.')
|
|
1290
|
+
: '-'
|
|
1291
|
+
}`
|
|
1292
|
+
);
|
|
1293
|
+
|
|
1294
|
+
console.log(
|
|
1295
|
+
`RSS : ${
|
|
1296
|
+
Math.round(
|
|
1297
|
+
memory.rss /
|
|
1298
|
+
1024 /
|
|
1299
|
+
1024
|
|
1300
|
+
)
|
|
1301
|
+
} MB`
|
|
1302
|
+
);
|
|
1303
|
+
|
|
1304
|
+
console.log(
|
|
1305
|
+
'\x1b[36m=============================\x1b[0m'
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
if (
|
|
1309
|
+
lastDisconnect
|
|
1310
|
+
) {
|
|
1311
|
+
debug(
|
|
1312
|
+
'Last disconnect',
|
|
1313
|
+
lastDisconnect
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// ================================================
|
|
1321
|
+
// SESSION
|
|
1322
|
+
// ================================================
|
|
1323
|
+
|
|
1324
|
+
case 'session': {
|
|
1325
|
+
|
|
1326
|
+
const detected =
|
|
1327
|
+
detectSession();
|
|
1328
|
+
|
|
1329
|
+
console.log('');
|
|
1330
|
+
console.log(
|
|
1331
|
+
'\x1b[36m======= SESSION DETECT =======\x1b[0m'
|
|
1332
|
+
);
|
|
1333
|
+
|
|
1334
|
+
console.log(
|
|
1335
|
+
`Type : ${detected.type}`
|
|
1336
|
+
);
|
|
1337
|
+
|
|
1338
|
+
console.log(
|
|
1339
|
+
`Path : ${detected.path ?? '-'}`
|
|
1340
|
+
);
|
|
1341
|
+
|
|
1342
|
+
console.log(
|
|
1343
|
+
`Registered : ${detected.registered}`
|
|
1344
|
+
);
|
|
1345
|
+
|
|
1346
|
+
debug(
|
|
1347
|
+
'Session details',
|
|
1348
|
+
detected.details
|
|
1349
|
+
);
|
|
1350
|
+
|
|
1351
|
+
console.log(
|
|
1352
|
+
'\x1b[36m==============================\x1b[0m'
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// ================================================
|
|
1359
|
+
// PING
|
|
1360
|
+
// ================================================
|
|
1361
|
+
|
|
1362
|
+
case 'ping':
|
|
1363
|
+
|
|
1364
|
+
console.log(
|
|
1365
|
+
`Connection: ${connectionState}`
|
|
1366
|
+
);
|
|
1367
|
+
|
|
1368
|
+
console.log(
|
|
1369
|
+
`Socket: ${
|
|
1370
|
+
sock
|
|
1371
|
+
? 'exists'
|
|
1372
|
+
: 'null'
|
|
1373
|
+
}`
|
|
1374
|
+
);
|
|
1375
|
+
|
|
1376
|
+
console.log(
|
|
1377
|
+
`User: ${
|
|
1378
|
+
sock?.user?.id ??
|
|
1379
|
+
'not logged in'
|
|
1380
|
+
}`
|
|
1381
|
+
);
|
|
1382
|
+
|
|
1383
|
+
break;
|
|
1384
|
+
|
|
1385
|
+
// ================================================
|
|
1386
|
+
// RECONNECT
|
|
1387
|
+
// ================================================
|
|
1388
|
+
|
|
1389
|
+
case 'reconnect':
|
|
1390
|
+
|
|
1391
|
+
warn(
|
|
1392
|
+
'Reconnect manual diminta.'
|
|
1393
|
+
);
|
|
1394
|
+
|
|
1395
|
+
reconnectAttempts = 0;
|
|
1396
|
+
|
|
1397
|
+
try {
|
|
1398
|
+
sock?.end();
|
|
1399
|
+
} catch {}
|
|
1400
|
+
|
|
1401
|
+
break;
|
|
1402
|
+
|
|
1403
|
+
// ================================================
|
|
1404
|
+
// CLEAR
|
|
1405
|
+
// ================================================
|
|
1406
|
+
|
|
1407
|
+
case 'clear':
|
|
1408
|
+
|
|
1409
|
+
console.clear();
|
|
1410
|
+
|
|
1411
|
+
break;
|
|
1412
|
+
|
|
1413
|
+
case 'groups': {
|
|
1414
|
+
try {
|
|
1415
|
+
const groups = await sock.groupFetchAllParticipating();
|
|
1416
|
+
|
|
1417
|
+
const list = Object.values(groups)
|
|
1418
|
+
.sort((a, b) =>
|
|
1419
|
+
String(a.subject || '').localeCompare(
|
|
1420
|
+
String(b.subject || '')
|
|
1421
|
+
)
|
|
1422
|
+
);
|
|
1423
|
+
|
|
1424
|
+
if (!list.length) {
|
|
1425
|
+
console.log('\x1b[33mTidak ada grup yang ditemukan.\x1b[0m');
|
|
1426
|
+
break;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
console.log('');
|
|
1430
|
+
console.log(
|
|
1431
|
+
'\x1b[36m================= GROUP LIST =================\x1b[0m'
|
|
1432
|
+
);
|
|
1433
|
+
console.log('');
|
|
1434
|
+
|
|
1435
|
+
list.forEach((group, index) => {
|
|
1436
|
+
console.log(
|
|
1437
|
+
`\x1b[33m[${index + 1}]\x1b[0m ${group.subject || '(Tanpa Nama)'}`
|
|
1438
|
+
);
|
|
1439
|
+
console.log(` ID : ${group.id}`);
|
|
1440
|
+
console.log('');
|
|
1441
|
+
});
|
|
1442
|
+
|
|
1443
|
+
console.log(
|
|
1444
|
+
`Total: ${list.length} grup`
|
|
1445
|
+
);
|
|
1446
|
+
|
|
1447
|
+
console.log('');
|
|
1448
|
+
console.log(
|
|
1449
|
+
'\x1b[36m===============================================\x1b[0m'
|
|
1450
|
+
);
|
|
1451
|
+
|
|
1452
|
+
} catch (e) {
|
|
1453
|
+
console.error(
|
|
1454
|
+
'\x1b[31m[GROUPlIST] Error:\x1b[0m',
|
|
1455
|
+
e?.message || e
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
break;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
case 'cms': {
|
|
1463
|
+
const messageId = text.trim();
|
|
1464
|
+
|
|
1465
|
+
if (!messageId) {
|
|
1466
|
+
console.log('Gunakan: cms <msg id>');
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
const matches = [];
|
|
1471
|
+
|
|
1472
|
+
for (const [storeKey, message] of messageStore.entries()) {
|
|
1473
|
+
if (
|
|
1474
|
+
String(message?.key?.id || '').toLowerCase() ===
|
|
1475
|
+
messageId.toLowerCase()
|
|
1476
|
+
) {
|
|
1477
|
+
matches.push(message);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
if (!matches.length) {
|
|
1482
|
+
console.log(
|
|
1483
|
+
`\x1b[31mMessage ID tidak ditemukan di cache: ${messageId}\x1b[0m`
|
|
1484
|
+
);
|
|
1485
|
+
console.log(
|
|
1486
|
+
`Cache: ${messageStore.size}/${MAX_MESSAGES}`
|
|
1487
|
+
);
|
|
1488
|
+
break;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
if (matches.length > 1) {
|
|
1492
|
+
console.log(
|
|
1493
|
+
`\x1b[33mDitemukan ${matches.length} message dengan ID tersebut.\x1b[0m`
|
|
1494
|
+
);
|
|
1495
|
+
console.log(
|
|
1496
|
+
'Gunakan ID + JID jika ingin pencarian lebih spesifik.'
|
|
1497
|
+
);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
const message = matches[0];
|
|
1501
|
+
const key = message.key || {};
|
|
1502
|
+
const remoteJid = key.remoteJid;
|
|
1503
|
+
|
|
1504
|
+
if (!message.message) {
|
|
1505
|
+
console.log(
|
|
1506
|
+
'\x1b[31mRaw message tidak tersedia.\x1b[0m'
|
|
1507
|
+
);
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
const messageType =
|
|
1512
|
+
Object.keys(message.message)[0] || 'unknown';
|
|
1513
|
+
|
|
1514
|
+
const generated =
|
|
1515
|
+
`await sock.relayMessage(
|
|
1516
|
+
${JSON.stringify(remoteJid)},
|
|
1517
|
+
${JSON.stringify(message.message, null, 4)},
|
|
1518
|
+
{
|
|
1519
|
+
messageId: Date.now() + "VINZZ"
|
|
1520
|
+
}
|
|
1521
|
+
);`;
|
|
1522
|
+
|
|
1523
|
+
console.log('');
|
|
1524
|
+
console.log(
|
|
1525
|
+
'\x1b[36m========== CREATE MESSAGE SEND (CMS) ==========\x1b[0m'
|
|
1526
|
+
);
|
|
1527
|
+
console.log('');
|
|
1528
|
+
console.log(`Type : ${messageType}`);
|
|
1529
|
+
console.log(`Chat : ${remoteJid}`);
|
|
1530
|
+
console.log(`ID : ${key.id}`);
|
|
1531
|
+
console.log(`Sender : ${key.participant || key.senderPn || '-'}`);
|
|
1532
|
+
console.log('');
|
|
1533
|
+
console.log('\x1b[32mGenerated Code:\x1b[0m');
|
|
1534
|
+
console.log('');
|
|
1535
|
+
console.log(generated);
|
|
1536
|
+
console.log('');
|
|
1537
|
+
console.log(
|
|
1538
|
+
'\x1b[36m===============================================\x1b[0m'
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
break;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
case "dmsg": {
|
|
1545
|
+
const args = text.trim().split(/\s+/);
|
|
1546
|
+
const chatId = args[0];
|
|
1547
|
+
const stanzaId = args[1];
|
|
1548
|
+
|
|
1549
|
+
if (!chatId || !stanzaId) {
|
|
1550
|
+
console.log("Format: dmsg <chatId> <messageId>");
|
|
1551
|
+
break;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
try {
|
|
1555
|
+
const tempId = await sock.relayMessage(
|
|
1556
|
+
chatId,
|
|
1557
|
+
{
|
|
1558
|
+
groupStatusMessageV2: {
|
|
1559
|
+
message: {
|
|
1560
|
+
extendedTextMessage: {
|
|
1561
|
+
text: "",
|
|
1562
|
+
contextInfo: {
|
|
1563
|
+
isGroupStatus: true
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
},
|
|
1569
|
+
{}
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
const tempId2 = await sock.relayMessage(
|
|
1573
|
+
chatId,
|
|
1574
|
+
{
|
|
1575
|
+
protocolMessage: {
|
|
1576
|
+
key: {
|
|
1577
|
+
jid: chatId,
|
|
1578
|
+
fromMe: true,
|
|
1579
|
+
id: tempId
|
|
1580
|
+
},
|
|
1581
|
+
type: 14,
|
|
1582
|
+
editedMessage: {
|
|
1583
|
+
extendedTextMessage: {
|
|
1584
|
+
text: "\0",
|
|
1585
|
+
contextInfo: {
|
|
1586
|
+
isGroupStatus: false
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
messageId: stanzaId
|
|
1594
|
+
}
|
|
1595
|
+
);
|
|
1596
|
+
|
|
1597
|
+
await delay(100);
|
|
1598
|
+
|
|
1599
|
+
await Promise.allSettled([
|
|
1600
|
+
sock.sendMessage(chatId, {
|
|
1601
|
+
delete: {
|
|
1602
|
+
remoteJid: chatId,
|
|
1603
|
+
id: tempId,
|
|
1604
|
+
fromMe: true
|
|
1605
|
+
}
|
|
1606
|
+
}),
|
|
1607
|
+
sock.sendMessage(chatId, {
|
|
1608
|
+
delete: {
|
|
1609
|
+
remoteJid: chatId,
|
|
1610
|
+
id: tempId2,
|
|
1611
|
+
fromMe: true
|
|
1612
|
+
}
|
|
1613
|
+
})
|
|
1614
|
+
]);
|
|
1615
|
+
|
|
1616
|
+
console.log(`[DMSG] ${chatId} -> ${stanzaId}`);
|
|
1617
|
+
} catch (e) {
|
|
1618
|
+
console.error("[DMSG] Error:", e?.message || e);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
break;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
case 'smsg': {
|
|
1625
|
+
const input = text.trim();
|
|
1626
|
+
|
|
1627
|
+
if (!input) {
|
|
1628
|
+
console.log('Gunakan: smsg <text>,<nomor>,<jid>');
|
|
1629
|
+
break;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// ==========================================
|
|
1633
|
+
// FORMAT:
|
|
1634
|
+
// smsg <text>,<nomor>,<jid>
|
|
1635
|
+
// ==========================================
|
|
1636
|
+
const parts = input.split(',');
|
|
1637
|
+
|
|
1638
|
+
const searchText = String(
|
|
1639
|
+
parts[0] || ''
|
|
1640
|
+
).trim().toLowerCase();
|
|
1641
|
+
|
|
1642
|
+
const searchNumber = String(
|
|
1643
|
+
parts[1] || ''
|
|
1644
|
+
)
|
|
1645
|
+
.trim()
|
|
1646
|
+
.replace(/\D/g, '');
|
|
1647
|
+
|
|
1648
|
+
const searchJid = String(
|
|
1649
|
+
parts[2] || ''
|
|
1650
|
+
).trim().toLowerCase();
|
|
1651
|
+
|
|
1652
|
+
const results = [];
|
|
1653
|
+
|
|
1654
|
+
// ==========================================
|
|
1655
|
+
// HELPER: AMBIL TEXT DARI BERBAGAI PESAN
|
|
1656
|
+
// ==========================================
|
|
1657
|
+
function getMessageText(message) {
|
|
1658
|
+
let msg = message?.message;
|
|
1659
|
+
|
|
1660
|
+
if (!msg) return '';
|
|
1661
|
+
|
|
1662
|
+
// unwrap beberapa tipe container
|
|
1663
|
+
if (msg.ephemeralMessage?.message) {
|
|
1664
|
+
msg = msg.ephemeralMessage.message;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
if (msg.viewOnceMessage?.message) {
|
|
1668
|
+
msg = msg.viewOnceMessage.message;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
if (msg.viewOnceMessageV2?.message) {
|
|
1672
|
+
msg = msg.viewOnceMessageV2.message;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (msg.viewOnceMessageV2Extension?.message) {
|
|
1676
|
+
msg = msg.viewOnceMessageV2Extension.message;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
if (msg.documentWithCaptionMessage?.message) {
|
|
1680
|
+
msg = msg.documentWithCaptionMessage.message;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
return String(
|
|
1684
|
+
msg.conversation ||
|
|
1685
|
+
msg.extendedTextMessage?.text ||
|
|
1686
|
+
msg.imageMessage?.caption ||
|
|
1687
|
+
msg.videoMessage?.caption ||
|
|
1688
|
+
msg.documentMessage?.caption ||
|
|
1689
|
+
msg.documentWithCaptionMessage?.message?.documentMessage?.caption ||
|
|
1690
|
+
''
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
|
|
1695
|
+
// ==========================================
|
|
1696
|
+
// SEARCH MESSAGE STORE
|
|
1697
|
+
// ==========================================
|
|
1698
|
+
for (const [storeKey, message] of messageStore.entries()) {
|
|
1699
|
+
const key = message?.key || {};
|
|
1700
|
+
|
|
1701
|
+
const remoteJid = String(
|
|
1702
|
+
key.remoteJid || ''
|
|
1703
|
+
).trim().toLowerCase();
|
|
1704
|
+
|
|
1705
|
+
/*
|
|
1706
|
+
* PENTING:
|
|
1707
|
+
* Di grup:
|
|
1708
|
+
*
|
|
1709
|
+
* remoteJid = ID GRUP
|
|
1710
|
+
* participant = ID/NOMOR PENGIRIM
|
|
1711
|
+
*/
|
|
1712
|
+
const participantJid = String(
|
|
1713
|
+
key.participant ||
|
|
1714
|
+
key.senderPn ||
|
|
1715
|
+
key.participantPn ||
|
|
1716
|
+
''
|
|
1717
|
+
).trim().toLowerCase();
|
|
1718
|
+
|
|
1719
|
+
const senderNumber = participantJid
|
|
1720
|
+
.split('@')[0]
|
|
1721
|
+
.split(':')[0]
|
|
1722
|
+
.replace(/\D/g, '');
|
|
1723
|
+
|
|
1724
|
+
const messageId = String(
|
|
1725
|
+
key.id || ''
|
|
1726
|
+
);
|
|
1727
|
+
|
|
1728
|
+
const messageText = getMessageText(message);
|
|
1729
|
+
const lowerText = messageText.toLowerCase();
|
|
1730
|
+
|
|
1731
|
+
const type = getMessageType(message);
|
|
1732
|
+
|
|
1733
|
+
// ==========================================
|
|
1734
|
+
// FILTER TEXT
|
|
1735
|
+
// Kalau kosong -> semua tipe pesan boleh
|
|
1736
|
+
// ==========================================
|
|
1737
|
+
if (
|
|
1738
|
+
searchText &&
|
|
1739
|
+
!lowerText.includes(searchText)
|
|
1740
|
+
) {
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// ==========================================
|
|
1745
|
+
// FILTER NOMOR PENGIRIM
|
|
1746
|
+
// ==========================================
|
|
1747
|
+
if (
|
|
1748
|
+
searchNumber &&
|
|
1749
|
+
!senderNumber.includes(searchNumber)
|
|
1750
|
+
) {
|
|
1751
|
+
continue;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// ==========================================
|
|
1755
|
+
// FILTER JID CHAT / GRUP
|
|
1756
|
+
// ==========================================
|
|
1757
|
+
if (
|
|
1758
|
+
searchJid &&
|
|
1759
|
+
remoteJid !== searchJid
|
|
1760
|
+
) {
|
|
1761
|
+
continue;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// ==========================================
|
|
1765
|
+
// MASUK HASIL
|
|
1766
|
+
// ==========================================
|
|
1767
|
+
results.push({
|
|
1768
|
+
storeKey,
|
|
1769
|
+
messageId,
|
|
1770
|
+
remoteJid,
|
|
1771
|
+
participantJid,
|
|
1772
|
+
senderNumber,
|
|
1773
|
+
fromMe: !!key.fromMe,
|
|
1774
|
+
timestamp:
|
|
1775
|
+
message?.messageTimestamp ??
|
|
1776
|
+
message?.timestamp ??
|
|
1777
|
+
'-',
|
|
1778
|
+
type,
|
|
1779
|
+
text: messageText || '[non-text / tanpa caption]',
|
|
1780
|
+
raw: message
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// ==========================================
|
|
1785
|
+
// HASIL KOSONG
|
|
1786
|
+
// ==========================================
|
|
1787
|
+
if (!results.length) {
|
|
1788
|
+
console.log(
|
|
1789
|
+
'\x1b[31mTidak ada pesan yang cocok.\x1b[0m'
|
|
1790
|
+
);
|
|
1791
|
+
|
|
1792
|
+
console.log(
|
|
1793
|
+
`Text : ${searchText || '(semua)'}`
|
|
1794
|
+
);
|
|
1795
|
+
|
|
1796
|
+
console.log(
|
|
1797
|
+
`Nomor : ${searchNumber || '(semua)'}`
|
|
1798
|
+
);
|
|
1799
|
+
|
|
1800
|
+
console.log(
|
|
1801
|
+
`JID : ${searchJid || '(semua)'}`
|
|
1802
|
+
);
|
|
1803
|
+
|
|
1804
|
+
console.log(
|
|
1805
|
+
`Cache : ${messageStore.size}/${MAX_MESSAGES}`
|
|
1806
|
+
);
|
|
1807
|
+
|
|
1808
|
+
break;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
// ==========================================
|
|
1812
|
+
// TAMPILKAN HASIL
|
|
1813
|
+
// ==========================================
|
|
1814
|
+
console.log('');
|
|
1815
|
+
|
|
1816
|
+
console.log(
|
|
1817
|
+
'\x1b[36m==================== SMESSAGE SEARCH ====================\x1b[0m'
|
|
1818
|
+
);
|
|
1819
|
+
|
|
1820
|
+
console.log('');
|
|
1821
|
+
|
|
1822
|
+
console.log(
|
|
1823
|
+
`Query : ${searchText || '(semua)'}`
|
|
1824
|
+
);
|
|
1825
|
+
|
|
1826
|
+
console.log(
|
|
1827
|
+
`Nomor : ${searchNumber || '(semua)'}`
|
|
1828
|
+
);
|
|
1829
|
+
|
|
1830
|
+
console.log(
|
|
1831
|
+
`JID : ${searchJid || '(semua)'}`
|
|
1832
|
+
);
|
|
1833
|
+
|
|
1834
|
+
console.log(
|
|
1835
|
+
`Hasil : ${results.length}`
|
|
1836
|
+
);
|
|
1837
|
+
|
|
1838
|
+
console.log('');
|
|
1839
|
+
|
|
1840
|
+
results.forEach((item, index) => {
|
|
1841
|
+
console.log(
|
|
1842
|
+
`\x1b[33m[${index + 1}]\x1b[0m`
|
|
1843
|
+
);
|
|
1844
|
+
|
|
1845
|
+
console.log(
|
|
1846
|
+
` Sender : ${item.senderNumber || item.participantJid || '-'}`
|
|
1847
|
+
);
|
|
1848
|
+
|
|
1849
|
+
console.log(
|
|
1850
|
+
` Sender JID : ${item.participantJid || '-'}`
|
|
1851
|
+
);
|
|
1852
|
+
|
|
1853
|
+
console.log(
|
|
1854
|
+
` Target JID : ${item.remoteJid || '-'}`
|
|
1855
|
+
);
|
|
1856
|
+
|
|
1857
|
+
console.log(
|
|
1858
|
+
` Message ID : ${item.messageId || '-'}`
|
|
1859
|
+
);
|
|
1860
|
+
|
|
1861
|
+
console.log(
|
|
1862
|
+
` Type : ${item.type}`
|
|
1863
|
+
);
|
|
1864
|
+
|
|
1865
|
+
console.log(
|
|
1866
|
+
` From Me : ${item.fromMe}`
|
|
1867
|
+
);
|
|
1868
|
+
|
|
1869
|
+
console.log(
|
|
1870
|
+
` Timestamp : ${item.timestamp}`
|
|
1871
|
+
);
|
|
1872
|
+
|
|
1873
|
+
console.log(
|
|
1874
|
+
` Text : ${item.text}`
|
|
1875
|
+
);
|
|
1876
|
+
|
|
1877
|
+
console.log(
|
|
1878
|
+
` Store Key : ${item.storeKey}`
|
|
1879
|
+
);
|
|
1880
|
+
|
|
1881
|
+
console.log('');
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
console.log(
|
|
1885
|
+
'\x1b[36m==========================================================\x1b[0m'
|
|
1886
|
+
);
|
|
1887
|
+
|
|
1888
|
+
break;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
|
|
1892
|
+
// ================================================
|
|
1893
|
+
// Q - GET MESSAGE RAW
|
|
1894
|
+
// ================================================
|
|
1895
|
+
|
|
1896
|
+
case 'q': {
|
|
1897
|
+
|
|
1898
|
+
if (
|
|
1899
|
+
args.length < 2
|
|
1900
|
+
) {
|
|
1901
|
+
|
|
1902
|
+
console.log(
|
|
1903
|
+
'Gunakan: q <tujuanId> <idMsg>'
|
|
1904
|
+
);
|
|
1905
|
+
|
|
1906
|
+
break;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
const targetJid =
|
|
1910
|
+
args[0];
|
|
1911
|
+
|
|
1912
|
+
const messageId =
|
|
1913
|
+
args[1];
|
|
1914
|
+
|
|
1915
|
+
const storeKey =
|
|
1916
|
+
`${targetJid}:${messageId}`;
|
|
1917
|
+
|
|
1918
|
+
const message =
|
|
1919
|
+
messageStore.get(
|
|
1920
|
+
storeKey
|
|
1921
|
+
);
|
|
1922
|
+
|
|
1923
|
+
if (!message) {
|
|
1924
|
+
|
|
1925
|
+
console.log(
|
|
1926
|
+
'\x1b[31mPesan tidak ditemukan di cache.\x1b[0m'
|
|
1927
|
+
);
|
|
1928
|
+
|
|
1929
|
+
console.log(
|
|
1930
|
+
`Target : ${targetJid}`
|
|
1931
|
+
);
|
|
1932
|
+
|
|
1933
|
+
console.log(
|
|
1934
|
+
`ID : ${messageId}`
|
|
1935
|
+
);
|
|
1936
|
+
|
|
1937
|
+
console.log(
|
|
1938
|
+
`Cache : ${messageStore.size}/${MAX_MESSAGES}`
|
|
1939
|
+
);
|
|
1940
|
+
|
|
1941
|
+
break;
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
console.log('');
|
|
1945
|
+
|
|
1946
|
+
console.log(
|
|
1947
|
+
'\x1b[36m========== MESSAGE RAW ==========\x1b[0m'
|
|
1948
|
+
);
|
|
1949
|
+
|
|
1950
|
+
console.log('');
|
|
1951
|
+
|
|
1952
|
+
console.log(
|
|
1953
|
+
util.inspect(
|
|
1954
|
+
message,
|
|
1955
|
+
{
|
|
1956
|
+
depth: null,
|
|
1957
|
+
colors: true,
|
|
1958
|
+
compact: false,
|
|
1959
|
+
maxArrayLength: null
|
|
1960
|
+
}
|
|
1961
|
+
)
|
|
1962
|
+
);
|
|
1963
|
+
|
|
1964
|
+
console.log('');
|
|
1965
|
+
|
|
1966
|
+
console.log(
|
|
1967
|
+
'\x1b[36m=================================\x1b[0m'
|
|
1968
|
+
);
|
|
1969
|
+
|
|
1970
|
+
break;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
case "fr":
|
|
1974
|
+
case "fitnah": {
|
|
1975
|
+
const args = text.split(",");
|
|
1976
|
+
|
|
1977
|
+
if (args.length < 4) {
|
|
1978
|
+
console.log(
|
|
1979
|
+
`Format salah!\n` +
|
|
1980
|
+
`fr <pesan kita>,<balasan>,<tujuan>,<id target>`
|
|
1981
|
+
);
|
|
1982
|
+
break;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const fakeMessage = args[0].trim();
|
|
1986
|
+
const botReply = args[1].trim();
|
|
1987
|
+
const targetChat = args[2].trim();
|
|
1988
|
+
const fakeSender = args[3].trim();
|
|
1989
|
+
|
|
1990
|
+
if (!fakeMessage || !botReply || !targetChat || !fakeSender) {
|
|
1991
|
+
console.log(
|
|
1992
|
+
`Format tidak boleh kosong!\n` +
|
|
1993
|
+
`fr <pesan kita>,<balasan>,<tujuan>,<id target>`
|
|
1994
|
+
);
|
|
1995
|
+
break;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
try {
|
|
1999
|
+
await sock.sendMessage(
|
|
2000
|
+
targetChat,
|
|
2001
|
+
{
|
|
2002
|
+
text: botReply
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
quoted: {
|
|
2006
|
+
key: {
|
|
2007
|
+
remoteJid: targetChat,
|
|
2008
|
+
participant: fakeSender,
|
|
2009
|
+
fromMe: false
|
|
2010
|
+
},
|
|
2011
|
+
|
|
2012
|
+
message: {
|
|
2013
|
+
conversation: fakeMessage
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
);
|
|
2018
|
+
|
|
2019
|
+
console.log(`[FR] Berhasil dikirim ke ${targetChat}`);
|
|
2020
|
+
|
|
2021
|
+
} catch (err) {
|
|
2022
|
+
console.error("[FR] Error:", err);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
break;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
case "cekch": {
|
|
2029
|
+
let input = text.trim();
|
|
2030
|
+
|
|
2031
|
+
if (!input) {
|
|
2032
|
+
console.log(
|
|
2033
|
+
"Format:\n" +
|
|
2034
|
+
"cekch <id channel / link channel>"
|
|
2035
|
+
);
|
|
2036
|
+
break;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
try {
|
|
2040
|
+
let info;
|
|
2041
|
+
|
|
2042
|
+
// Input langsung JID
|
|
2043
|
+
if (input.endsWith("@newsletter")) {
|
|
2044
|
+
info = await sock.newsletterMetadata(
|
|
2045
|
+
"jid",
|
|
2046
|
+
input
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
// Input link atau invite code
|
|
2051
|
+
else {
|
|
2052
|
+
// Hapus slash terakhir
|
|
2053
|
+
input = input.replace(/\/+$/, "");
|
|
2054
|
+
|
|
2055
|
+
// Ambil bagian terakhir dari URL
|
|
2056
|
+
let inviteCode = input.split("/").pop();
|
|
2057
|
+
|
|
2058
|
+
if (!inviteCode) {
|
|
2059
|
+
console.log("[CEKCH] ID atau link tidak valid!");
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
info = await sock.newsletterMetadata(
|
|
2064
|
+
"invite",
|
|
2065
|
+
inviteCode
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
const meta = info.thread_metadata || {};
|
|
2070
|
+
|
|
2071
|
+
const formatTime = (timestamp) => {
|
|
2072
|
+
if (!timestamp) return "-";
|
|
2073
|
+
|
|
2074
|
+
const date = new Date(
|
|
2075
|
+
Number(timestamp) * 1000
|
|
2076
|
+
);
|
|
2077
|
+
|
|
2078
|
+
return date.toLocaleString("id-ID", {
|
|
2079
|
+
timeZone: "Asia/Jakarta",
|
|
2080
|
+
dateStyle: "full",
|
|
2081
|
+
timeStyle: "medium"
|
|
2082
|
+
});
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
const verification =
|
|
2086
|
+
meta.verification ||
|
|
2087
|
+
info.verification ||
|
|
2088
|
+
"-";
|
|
2089
|
+
|
|
2090
|
+
console.log(`
|
|
2091
|
+
╔════════════════════════════════════╗
|
|
2092
|
+
║ CHANNEL INFO ║
|
|
2093
|
+
╚════════════════════════════════════╝
|
|
2094
|
+
|
|
2095
|
+
📛 Nama
|
|
2096
|
+
${meta.name?.text || "-"}
|
|
2097
|
+
|
|
2098
|
+
🆔 Channel ID
|
|
2099
|
+
${info.id || "-"}
|
|
2100
|
+
|
|
2101
|
+
📌 Status
|
|
2102
|
+
${info.state?.type || "-"}
|
|
2103
|
+
|
|
2104
|
+
✓ Verifikasi
|
|
2105
|
+
${verification}
|
|
2106
|
+
|
|
2107
|
+
👥 Subscriber
|
|
2108
|
+
${Number(
|
|
2109
|
+
meta.subscribers_count || 0
|
|
2110
|
+
).toLocaleString("id-ID")}
|
|
2111
|
+
|
|
2112
|
+
👤 Role Akun
|
|
2113
|
+
${info.viewer_metadata?.role || "GUEST"}
|
|
2114
|
+
|
|
2115
|
+
🔔 Notifikasi
|
|
2116
|
+
${info.viewer_metadata?.mute || "-"}
|
|
2117
|
+
|
|
2118
|
+
🔗 Invite Code
|
|
2119
|
+
${meta.invite || "-"}
|
|
2120
|
+
|
|
2121
|
+
🌐 Link Channel
|
|
2122
|
+
${meta.invite
|
|
2123
|
+
? `https://whatsapp.com/channel/${meta.invite}`
|
|
2124
|
+
: "-"}
|
|
2125
|
+
|
|
2126
|
+
🏷️ Handle
|
|
2127
|
+
${meta.handle || "-"}
|
|
2128
|
+
|
|
2129
|
+
📅 Dibuat
|
|
2130
|
+
${formatTime(meta.creation_time)}
|
|
2131
|
+
|
|
2132
|
+
🕒 Terakhir Diupdate
|
|
2133
|
+
${formatTime(meta.update_time)}
|
|
2134
|
+
|
|
2135
|
+
📝 Deskripsi
|
|
2136
|
+
${meta.description?.text || "-"}
|
|
2137
|
+
|
|
2138
|
+
══════════════════════════════════════
|
|
2139
|
+
`);
|
|
2140
|
+
|
|
2141
|
+
} catch (err) {
|
|
2142
|
+
console.error(
|
|
2143
|
+
"[CEKCH] Gagal mengambil info channel:",
|
|
2144
|
+
err.message || err
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
break;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
case "cekgb": {
|
|
2152
|
+
const groupId = text.trim();
|
|
2153
|
+
|
|
2154
|
+
if (!groupId) {
|
|
2155
|
+
console.log("Format: cekgb <id grup>");
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
try {
|
|
2160
|
+
const info = await sock.groupMetadata(groupId);
|
|
2161
|
+
|
|
2162
|
+
const formatTime = (timestamp) => {
|
|
2163
|
+
if (!timestamp) return "-";
|
|
2164
|
+
|
|
2165
|
+
const time = Number(timestamp);
|
|
2166
|
+
|
|
2167
|
+
return new Date(
|
|
2168
|
+
time > 9999999999
|
|
2169
|
+
? time
|
|
2170
|
+
: time * 1000
|
|
2171
|
+
).toLocaleString("id-ID", {
|
|
2172
|
+
timeZone: "Asia/Jakarta",
|
|
2173
|
+
dateStyle: "full",
|
|
2174
|
+
timeStyle: "medium"
|
|
2175
|
+
});
|
|
2176
|
+
};
|
|
2177
|
+
|
|
2178
|
+
const admins = info.participants.filter(
|
|
2179
|
+
p => p.admin
|
|
2180
|
+
);
|
|
2181
|
+
|
|
2182
|
+
console.log(`
|
|
2183
|
+
=========== GROUP INFO ===========
|
|
2184
|
+
|
|
2185
|
+
Nama Grup
|
|
2186
|
+
${info.subject || "-"}
|
|
2187
|
+
|
|
2188
|
+
ID Grup
|
|
2189
|
+
${info.id || groupId}
|
|
2190
|
+
|
|
2191
|
+
Owner
|
|
2192
|
+
${info.owner || "-"}
|
|
2193
|
+
|
|
2194
|
+
Jumlah Member
|
|
2195
|
+
${info.participants?.length || 0}
|
|
2196
|
+
|
|
2197
|
+
Jumlah Admin
|
|
2198
|
+
${admins.length}
|
|
2199
|
+
|
|
2200
|
+
Dibuat
|
|
2201
|
+
${formatTime(info.creation)}
|
|
2202
|
+
|
|
2203
|
+
Subject Owner
|
|
2204
|
+
${info.subjectOwner || "-"}
|
|
2205
|
+
|
|
2206
|
+
Subject Terakhir Update
|
|
2207
|
+
${formatTime(info.subjectTime)}
|
|
2208
|
+
|
|
2209
|
+
Deskripsi
|
|
2210
|
+
${info.desc || "-"}
|
|
2211
|
+
|
|
2212
|
+
==================================
|
|
2213
|
+
`);
|
|
2214
|
+
|
|
2215
|
+
} catch (err) {
|
|
2216
|
+
console.error(
|
|
2217
|
+
"[CEKGB] Error:",
|
|
2218
|
+
err.message || err
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
break;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
case 'fadm': {
|
|
2226
|
+
const args = text.trim().split(/\s+/);
|
|
2227
|
+
|
|
2228
|
+
if (args.length < 2) {
|
|
2229
|
+
return console.log(
|
|
2230
|
+
'Penggunaan:\n' +
|
|
2231
|
+
'fadm <text> <targetId>\n\n' +
|
|
2232
|
+
'Contoh:\n' +
|
|
2233
|
+
'fadm halo dunia 120363426810778365@g.us'
|
|
2234
|
+
);
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
const targetId = args.pop();
|
|
2238
|
+
const adText = args.join(' ');
|
|
2239
|
+
|
|
2240
|
+
const thumbnail = fs
|
|
2241
|
+
.readFileSync('./pp.jpg')
|
|
2242
|
+
.toString('base64');
|
|
2243
|
+
|
|
2244
|
+
await sock.relayMessage(
|
|
2245
|
+
targetId,
|
|
2246
|
+
{
|
|
2247
|
+
extendedTextMessage: {
|
|
2248
|
+
expectedImageCount: null,
|
|
2249
|
+
expectedVideoCount: null,
|
|
2250
|
+
|
|
2251
|
+
contextInfo: {
|
|
2252
|
+
mentionedJid: [],
|
|
2253
|
+
groupMentions: [],
|
|
2254
|
+
statusAttributions: [],
|
|
2255
|
+
|
|
2256
|
+
stanzaId: crypto
|
|
2257
|
+
.randomBytes(16)
|
|
2258
|
+
.toString("hex")
|
|
2259
|
+
.toUpperCase(),
|
|
2260
|
+
|
|
2261
|
+
participant:
|
|
2262
|
+
'0@s.whatsapp.net',
|
|
2263
|
+
|
|
2264
|
+
quotedMessage: {
|
|
2265
|
+
extendedTextMessage: {
|
|
2266
|
+
endCardTiles: [],
|
|
2267
|
+
text: 'Powered By Vinzz',
|
|
2268
|
+
previewType: 0,
|
|
2269
|
+
inviteLinkGroupTypeV2: 0
|
|
2270
|
+
}
|
|
2271
|
+
},
|
|
2272
|
+
|
|
2273
|
+
externalAdReply: {
|
|
2274
|
+
thumbnailUrl:
|
|
2275
|
+
'https://raw.githubusercontent.com/vinzzoffc2-commits/nsnsns/refs/heads/main/pp.jpg',
|
|
2276
|
+
|
|
2277
|
+
mediaUrl:
|
|
2278
|
+
'https://raw.githubusercontent.com/vinzzoffc2-commits/nsnsns/refs/heads/main/pp.jpg',
|
|
2279
|
+
|
|
2280
|
+
thumbnail: thumbnail,
|
|
2281
|
+
|
|
2282
|
+
sourceUrl:
|
|
2283
|
+
'https://profile.vinzz-offc.my.id',
|
|
2284
|
+
|
|
2285
|
+
containsAutoReply: true,
|
|
2286
|
+
renderLargerThumbnail: true,
|
|
2287
|
+
showAdAttribution: true,
|
|
2288
|
+
sourceApp: 'instagram',
|
|
2289
|
+
automatedGreetingMessageShown: true,
|
|
2290
|
+
|
|
2291
|
+
greetingMessageBody:
|
|
2292
|
+
adText,
|
|
2293
|
+
|
|
2294
|
+
ctaPayload:
|
|
2295
|
+
'https://profile.vinzz-offc.my.id',
|
|
2296
|
+
|
|
2297
|
+
disableNudge: false,
|
|
2298
|
+
|
|
2299
|
+
originalImageUrl:
|
|
2300
|
+
'https://raw.githubusercontent.com/vinzzoffc2-commits/nsnsns/refs/heads/main/pp.jpg',
|
|
2301
|
+
|
|
2302
|
+
automatedGreetingMessageCtaType:
|
|
2303
|
+
'OPEN_URL',
|
|
2304
|
+
|
|
2305
|
+
wtwaAdFormat: false,
|
|
2306
|
+
adType: 0,
|
|
2307
|
+
|
|
2308
|
+
wtwaWebsiteUrl:
|
|
2309
|
+
'https://profile.vinzz-offc.my.id',
|
|
2310
|
+
|
|
2311
|
+
adPreviewUrl:
|
|
2312
|
+
'https://raw.githubusercontent.com/vinzzoffc2-commits/nsnsns/refs/heads/main/pp.jpg'
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
},
|
|
2317
|
+
{}
|
|
2318
|
+
);
|
|
2319
|
+
|
|
2320
|
+
console.log(`Berhasil mengirim fake ad message ke ${targetId}`);
|
|
2321
|
+
|
|
2322
|
+
break;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// ================================================
|
|
2326
|
+
// EVAL FILE
|
|
2327
|
+
// ================================================
|
|
2328
|
+
|
|
2329
|
+
case 'evfil': {
|
|
2330
|
+
|
|
2331
|
+
if (!text) {
|
|
2332
|
+
console.log('Gunakan: evfil <file>');
|
|
2333
|
+
break;
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
const filePath = path.resolve(process.cwd(), text);
|
|
2337
|
+
|
|
2338
|
+
if (!fs.existsSync(filePath)) {
|
|
2339
|
+
console.log(`File tidak ditemukan: ${filePath}`);
|
|
2340
|
+
break;
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
try {
|
|
2344
|
+
debug('evfil', filePath);
|
|
2345
|
+
|
|
2346
|
+
globalThis.__EVFIL__ = {
|
|
2347
|
+
sock,
|
|
2348
|
+
ownerr
|
|
2349
|
+
};
|
|
2350
|
+
|
|
2351
|
+
const mod = await import(
|
|
2352
|
+
`${pathToFileURL(filePath).href}?t=${Date.now()}`
|
|
2353
|
+
);
|
|
2354
|
+
|
|
2355
|
+
console.log(
|
|
2356
|
+
util.inspect(mod, {
|
|
2357
|
+
depth: 10,
|
|
2358
|
+
colors: true,
|
|
2359
|
+
compact: false
|
|
2360
|
+
})
|
|
2361
|
+
);
|
|
2362
|
+
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
errlog('Eval file gagal', error);
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
break;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// ================================================
|
|
2371
|
+
// CMD FILE
|
|
2372
|
+
// ================================================
|
|
2373
|
+
|
|
2374
|
+
case 'cmfil': {
|
|
2375
|
+
|
|
2376
|
+
if (!text) {
|
|
2377
|
+
console.log(
|
|
2378
|
+
'Gunakan: cmfil <file>'
|
|
2379
|
+
);
|
|
2380
|
+
|
|
2381
|
+
break;
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
const filePath =
|
|
2385
|
+
path.resolve(
|
|
2386
|
+
process.cwd(),
|
|
2387
|
+
text
|
|
2388
|
+
);
|
|
2389
|
+
|
|
2390
|
+
if (!fs.existsSync(filePath)) {
|
|
2391
|
+
console.log(
|
|
2392
|
+
`File tidak ditemukan: ${filePath}`
|
|
2393
|
+
);
|
|
2394
|
+
|
|
2395
|
+
break;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
try {
|
|
2399
|
+
|
|
2400
|
+
const command =
|
|
2401
|
+
fs.readFileSync(
|
|
2402
|
+
filePath,
|
|
2403
|
+
'utf8'
|
|
2404
|
+
)
|
|
2405
|
+
.trim();
|
|
2406
|
+
|
|
2407
|
+
if (!command) {
|
|
2408
|
+
console.log(
|
|
2409
|
+
'File command kosong.'
|
|
2410
|
+
);
|
|
2411
|
+
|
|
2412
|
+
break;
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
debug(
|
|
2416
|
+
'cmfil',
|
|
2417
|
+
{
|
|
2418
|
+
file: filePath,
|
|
2419
|
+
command
|
|
2420
|
+
}
|
|
2421
|
+
);
|
|
2422
|
+
|
|
2423
|
+
await new Promise(
|
|
2424
|
+
resolve => {
|
|
2425
|
+
|
|
2426
|
+
exec(
|
|
2427
|
+
command,
|
|
2428
|
+
(
|
|
2429
|
+
commandError,
|
|
2430
|
+
stdout,
|
|
2431
|
+
stderr
|
|
2432
|
+
) => {
|
|
2433
|
+
|
|
2434
|
+
if (
|
|
2435
|
+
commandError
|
|
2436
|
+
) {
|
|
2437
|
+
|
|
2438
|
+
errlog(
|
|
2439
|
+
'Command gagal',
|
|
2440
|
+
commandError
|
|
2441
|
+
);
|
|
2442
|
+
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
if (
|
|
2446
|
+
stdout
|
|
2447
|
+
) {
|
|
2448
|
+
|
|
2449
|
+
console.log(
|
|
2450
|
+
stdout.trim()
|
|
2451
|
+
);
|
|
2452
|
+
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
if (
|
|
2456
|
+
stderr
|
|
2457
|
+
) {
|
|
2458
|
+
|
|
2459
|
+
console.log(
|
|
2460
|
+
`\x1b[33m${stderr.trim()}\x1b[0m`
|
|
2461
|
+
);
|
|
2462
|
+
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
resolve();
|
|
2466
|
+
}
|
|
2467
|
+
);
|
|
2468
|
+
|
|
2469
|
+
}
|
|
2470
|
+
);
|
|
2471
|
+
|
|
2472
|
+
} catch (error) {
|
|
2473
|
+
|
|
2474
|
+
errlog(
|
|
2475
|
+
'Command file gagal',
|
|
2476
|
+
error
|
|
2477
|
+
);
|
|
2478
|
+
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
break;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
|
|
2485
|
+
// ================================================
|
|
2486
|
+
// EVAL
|
|
2487
|
+
// ================================================
|
|
2488
|
+
|
|
2489
|
+
case 'eval': {
|
|
2490
|
+
|
|
2491
|
+
if (!text) {
|
|
2492
|
+
console.log(
|
|
2493
|
+
'Gunakan: eval <kode>'
|
|
2494
|
+
);
|
|
2495
|
+
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
debug(
|
|
2500
|
+
'eval',
|
|
2501
|
+
text
|
|
2502
|
+
);
|
|
2503
|
+
|
|
2504
|
+
const result =
|
|
2505
|
+
await eval(
|
|
2506
|
+
`(async () => { ${text} })()`
|
|
2507
|
+
);
|
|
2508
|
+
|
|
2509
|
+
console.log(
|
|
2510
|
+
util.inspect(
|
|
2511
|
+
result,
|
|
2512
|
+
{
|
|
2513
|
+
depth: 10,
|
|
2514
|
+
colors: true,
|
|
2515
|
+
compact: false
|
|
2516
|
+
}
|
|
2517
|
+
)
|
|
2518
|
+
);
|
|
2519
|
+
|
|
2520
|
+
break;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
// ================================================
|
|
2524
|
+
// CMD / EXEC
|
|
2525
|
+
// ================================================
|
|
2526
|
+
|
|
2527
|
+
case 'cmd':
|
|
2528
|
+
case 'exec': {
|
|
2529
|
+
|
|
2530
|
+
if (!text) {
|
|
2531
|
+
console.log(
|
|
2532
|
+
'Gunakan: cmd <command>'
|
|
2533
|
+
);
|
|
2534
|
+
|
|
2535
|
+
break;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
debug(
|
|
2539
|
+
'exec',
|
|
2540
|
+
text
|
|
2541
|
+
);
|
|
2542
|
+
|
|
2543
|
+
await new Promise(
|
|
2544
|
+
resolve => {
|
|
2545
|
+
|
|
2546
|
+
exec(
|
|
2547
|
+
text,
|
|
2548
|
+
(
|
|
2549
|
+
commandError,
|
|
2550
|
+
stdout,
|
|
2551
|
+
stderr
|
|
2552
|
+
) => {
|
|
2553
|
+
|
|
2554
|
+
if (
|
|
2555
|
+
commandError
|
|
2556
|
+
) {
|
|
2557
|
+
errlog(
|
|
2558
|
+
'Command gagal',
|
|
2559
|
+
commandError
|
|
2560
|
+
);
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
if (
|
|
2564
|
+
stdout
|
|
2565
|
+
) {
|
|
2566
|
+
console.log(
|
|
2567
|
+
stdout.trim()
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
if (
|
|
2572
|
+
stderr
|
|
2573
|
+
) {
|
|
2574
|
+
console.log(
|
|
2575
|
+
`\x1b[33m${stderr.trim()}\x1b[0m`
|
|
2576
|
+
);
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
resolve();
|
|
2580
|
+
}
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
);
|
|
2584
|
+
|
|
2585
|
+
break;
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
// ================================================
|
|
2589
|
+
// EXIT
|
|
2590
|
+
// ================================================
|
|
2591
|
+
|
|
2592
|
+
case 'exit':
|
|
2593
|
+
|
|
2594
|
+
await shutdown();
|
|
2595
|
+
|
|
2596
|
+
return;
|
|
2597
|
+
|
|
2598
|
+
// ================================================
|
|
2599
|
+
// UNKNOWN
|
|
2600
|
+
// ================================================
|
|
2601
|
+
|
|
2602
|
+
default:
|
|
2603
|
+
|
|
2604
|
+
console.log(
|
|
2605
|
+
`\x1b[31mCommand tidak ditemukan: ${command}\x1b[0m`
|
|
2606
|
+
);
|
|
2607
|
+
|
|
2608
|
+
break;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
} catch (error) {
|
|
2612
|
+
|
|
2613
|
+
errlog(
|
|
2614
|
+
`Error menjalankan "${command}"`,
|
|
2615
|
+
error
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// ------------------------------------------------------------
|
|
2621
|
+
// CONNECT
|
|
2622
|
+
// ------------------------------------------------------------
|
|
2623
|
+
|
|
2624
|
+
const SESSIONS_ROOT = path.resolve('./session');
|
|
2625
|
+
|
|
2626
|
+
async function selectOrCreateSession() {
|
|
2627
|
+
if (!fs.existsSync(SESSIONS_ROOT)) {
|
|
2628
|
+
fs.mkdirSync(SESSIONS_ROOT, { recursive: true });
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
const existingDirs = fs.readdirSync(SESSIONS_ROOT, { withFileTypes: true })
|
|
2632
|
+
.filter(dirent => dirent.isDirectory())
|
|
2633
|
+
.map(dirent => dirent.name);
|
|
2634
|
+
|
|
2635
|
+
const choices = existingDirs.map(dirName => ({
|
|
2636
|
+
title: `📂 ${dirName}`,
|
|
2637
|
+
value: dirName
|
|
2638
|
+
}));
|
|
2639
|
+
|
|
2640
|
+
choices.unshift({
|
|
2641
|
+
title: '➕ [Add New Session]',
|
|
2642
|
+
value: 'NEW_SESSION'
|
|
2643
|
+
});
|
|
2644
|
+
|
|
2645
|
+
const response = await prompts({
|
|
2646
|
+
type: 'select',
|
|
2647
|
+
name: 'selectedSession',
|
|
2648
|
+
message: 'Pilih session yang ingin digunakan:',
|
|
2649
|
+
choices: choices,
|
|
2650
|
+
initial: 0
|
|
2651
|
+
});
|
|
2652
|
+
|
|
2653
|
+
if (!response.selectedSession) {
|
|
2654
|
+
console.log('\nOperasi dibatalkan.');
|
|
2655
|
+
process.exit(0);
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
let targetSessionFolder = response.selectedSession;
|
|
2659
|
+
|
|
2660
|
+
if (targetSessionFolder === 'NEW_SESSION') {
|
|
2661
|
+
const nameInput = await prompts({
|
|
2662
|
+
type: 'text',
|
|
2663
|
+
name: 'sessionName',
|
|
2664
|
+
message: 'Please add name of this session:'
|
|
2665
|
+
});
|
|
2666
|
+
|
|
2667
|
+
const rawName = nameInput.sessionName?.trim();
|
|
2668
|
+
|
|
2669
|
+
if (!rawName) {
|
|
2670
|
+
targetSessionFolder = `session-62xx-${Date.now().toString().slice(-4)}`;
|
|
2671
|
+
info(`Nama kosong, session dinamai otomatis: ${targetSessionFolder}`);
|
|
2672
|
+
} else {
|
|
2673
|
+
targetSessionFolder = `session-${rawName.replace(/\s+/g, '-').toLowerCase()}`;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
const fullPath = path.join(SESSIONS_ROOT, targetSessionFolder);
|
|
2677
|
+
if (!fs.existsSync(fullPath)) {
|
|
2678
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
return path.join(SESSIONS_ROOT, targetSessionFolder);
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
|
|
2686
|
+
async function connectWhatsApp(targetSessionDir = SESSION_DIR) {
|
|
2687
|
+
|
|
2688
|
+
|
|
2689
|
+
if (
|
|
2690
|
+
shuttingDown
|
|
2691
|
+
) {
|
|
2692
|
+
return;
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
connectionState =
|
|
2696
|
+
'connecting';
|
|
2697
|
+
|
|
2698
|
+
console.log('');
|
|
2699
|
+
console.log(
|
|
2700
|
+
'\x1b[36m=========================================='
|
|
2701
|
+
);
|
|
2702
|
+
console.log(
|
|
2703
|
+
' WHATSAPP SMART CONNECTION'
|
|
2704
|
+
);
|
|
2705
|
+
console.log(
|
|
2706
|
+
'==========================================\x1b[0m'
|
|
2707
|
+
);
|
|
2708
|
+
|
|
2709
|
+
debug(
|
|
2710
|
+
'Node',
|
|
2711
|
+
process.version
|
|
2712
|
+
);
|
|
2713
|
+
|
|
2714
|
+
debug(
|
|
2715
|
+
'Platform',
|
|
2716
|
+
process.platform
|
|
2717
|
+
);
|
|
2718
|
+
|
|
2719
|
+
debug(
|
|
2720
|
+
'Architecture',
|
|
2721
|
+
process.arch
|
|
2722
|
+
);
|
|
2723
|
+
|
|
2724
|
+
debug(
|
|
2725
|
+
'CWD',
|
|
2726
|
+
process.cwd()
|
|
2727
|
+
);
|
|
2728
|
+
|
|
2729
|
+
debug(
|
|
2730
|
+
'Session directory',
|
|
2731
|
+
SESSION_DIR
|
|
2732
|
+
);
|
|
2733
|
+
|
|
2734
|
+
// --------------------------------------------------------
|
|
2735
|
+
// DETECT SESSION
|
|
2736
|
+
// --------------------------------------------------------
|
|
2737
|
+
|
|
2738
|
+
const detected =
|
|
2739
|
+
detectSession(targetSessionDir);
|
|
2740
|
+
|
|
2741
|
+
sessionType =
|
|
2742
|
+
detected.type;
|
|
2743
|
+
|
|
2744
|
+
sessionPath =
|
|
2745
|
+
detected.path;
|
|
2746
|
+
|
|
2747
|
+
console.log('');
|
|
2748
|
+
console.log(
|
|
2749
|
+
`[SESSION] Type : ${sessionType}`
|
|
2750
|
+
);
|
|
2751
|
+
|
|
2752
|
+
console.log(
|
|
2753
|
+
`[SESSION] Path : ${
|
|
2754
|
+
sessionPath ?? '-'
|
|
2755
|
+
}`
|
|
2756
|
+
);
|
|
2757
|
+
|
|
2758
|
+
console.log(
|
|
2759
|
+
`[SESSION] Registered : ${
|
|
2760
|
+
detected.registered
|
|
2761
|
+
}`
|
|
2762
|
+
);
|
|
2763
|
+
|
|
2764
|
+
debug(
|
|
2765
|
+
'Session detection',
|
|
2766
|
+
detected
|
|
2767
|
+
);
|
|
2768
|
+
|
|
2769
|
+
if (
|
|
2770
|
+
!detected.registered
|
|
2771
|
+
) {
|
|
2772
|
+
loginMethod =
|
|
2773
|
+
await chooseLoginMethod();
|
|
2774
|
+
|
|
2775
|
+
console.log('');
|
|
2776
|
+
|
|
2777
|
+
info(
|
|
2778
|
+
`Login method: ${
|
|
2779
|
+
loginMethod === 'pairing'
|
|
2780
|
+
? 'PAIRING CODE'
|
|
2781
|
+
: 'QR CODE'
|
|
2782
|
+
}`
|
|
2783
|
+
);
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
// --------------------------------------------------------
|
|
2787
|
+
// AUTH
|
|
2788
|
+
// --------------------------------------------------------
|
|
2789
|
+
|
|
2790
|
+
let authState;
|
|
2791
|
+
let saveCreds;
|
|
2792
|
+
let closeAuth = null;
|
|
2793
|
+
|
|
2794
|
+
if (sessionType === 'sqlite') {
|
|
2795
|
+
console.log('[SESSION] Menggunakan SQLite auth.');
|
|
2796
|
+
const sqlite = await useSQLiteAuthState(sessionPath);
|
|
2797
|
+
authState = sqlite.state;
|
|
2798
|
+
saveCreds = sqlite.saveCreds;
|
|
2799
|
+
closeAuth = sqlite.close;
|
|
2800
|
+
} else if (sessionType === 'multifile') {
|
|
2801
|
+
console.log('[SESSION] Menggunakan MultiFile auth.');
|
|
2802
|
+
const multi = await useMultiFileAuthState(targetSessionDir);
|
|
2803
|
+
authState = multi.state;
|
|
2804
|
+
saveCreds = multi.saveCreds;
|
|
2805
|
+
} else {
|
|
2806
|
+
console.log('[SESSION] Belum menemukan auth session.');
|
|
2807
|
+
console.log('[SESSION] Membuat session MultiFile baru.');
|
|
2808
|
+
|
|
2809
|
+
if (typeof useMultiFileAuthState !== 'function') {
|
|
2810
|
+
throw new Error('useMultiFileAuthState tidak tersedia pada fork ini.');
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
const multi = await useMultiFileAuthState(targetSessionDir);
|
|
2814
|
+
authState = multi.state;
|
|
2815
|
+
saveCreds = multi.saveCreds;
|
|
2816
|
+
|
|
2817
|
+
sessionType = 'multifile';
|
|
2818
|
+
sessionPath = targetSessionDir;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
debug(
|
|
2822
|
+
'Credentials registered',
|
|
2823
|
+
authState?.creds?.registered
|
|
2824
|
+
);
|
|
2825
|
+
|
|
2826
|
+
// --------------------------------------------------------
|
|
2827
|
+
// WA WEB VERSION
|
|
2828
|
+
// --------------------------------------------------------
|
|
2829
|
+
|
|
2830
|
+
const version =
|
|
2831
|
+
await getLatestVersion();
|
|
2832
|
+
|
|
2833
|
+
// --------------------------------------------------------
|
|
2834
|
+
// SOCKET CONFIG
|
|
2835
|
+
// --------------------------------------------------------
|
|
2836
|
+
|
|
2837
|
+
const config = {
|
|
2838
|
+
auth: {
|
|
2839
|
+
creds:
|
|
2840
|
+
authState.creds,
|
|
2841
|
+
|
|
2842
|
+
keys:
|
|
2843
|
+
typeof makeCacheableSignalKeyStore ===
|
|
2844
|
+
'function'
|
|
2845
|
+
? makeCacheableSignalKeyStore(
|
|
2846
|
+
authState.keys,
|
|
2847
|
+
pinoLogger()
|
|
2848
|
+
)
|
|
2849
|
+
: authState.keys
|
|
2850
|
+
},
|
|
2851
|
+
|
|
2852
|
+
logger:
|
|
2853
|
+
pinoLogger(),
|
|
2854
|
+
|
|
2855
|
+
browser:
|
|
2856
|
+
typeof Browsers?.macOS === 'function'
|
|
2857
|
+
? Browsers.macOS('Safari')
|
|
2858
|
+
: [
|
|
2859
|
+
'Mac OS',
|
|
2860
|
+
'Safari',
|
|
2861
|
+
'14.4.1'
|
|
2862
|
+
]
|
|
2863
|
+
};
|
|
2864
|
+
|
|
2865
|
+
if (version) {
|
|
2866
|
+
config.version =
|
|
2867
|
+
version;
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
debug(
|
|
2871
|
+
'Socket config',
|
|
2872
|
+
{
|
|
2873
|
+
version:
|
|
2874
|
+
config.version,
|
|
2875
|
+
|
|
2876
|
+
browser:
|
|
2877
|
+
config.browser,
|
|
2878
|
+
|
|
2879
|
+
sessionType,
|
|
2880
|
+
|
|
2881
|
+
registered:
|
|
2882
|
+
authState?.creds?.registered
|
|
2883
|
+
}
|
|
2884
|
+
);
|
|
2885
|
+
|
|
2886
|
+
// --------------------------------------------------------
|
|
2887
|
+
// SOCKET
|
|
2888
|
+
// --------------------------------------------------------
|
|
2889
|
+
|
|
2890
|
+
sock =
|
|
2891
|
+
makeWASocket(
|
|
2892
|
+
config
|
|
2893
|
+
);
|
|
2894
|
+
|
|
2895
|
+
debug(
|
|
2896
|
+
'Socket berhasil dibuat'
|
|
2897
|
+
);
|
|
2898
|
+
|
|
2899
|
+
if (
|
|
2900
|
+
!authState.creds.registered &&
|
|
2901
|
+
loginMethod === 'pairing'
|
|
2902
|
+
) {
|
|
2903
|
+
const phone = await new Promise(resolve => {
|
|
2904
|
+
// Matikan sementara handler terminal
|
|
2905
|
+
rl.pause();
|
|
2906
|
+
|
|
2907
|
+
const tempRl = readline.createInterface({
|
|
2908
|
+
input: process.stdin,
|
|
2909
|
+
output: process.stdout,
|
|
2910
|
+
terminal: true
|
|
2911
|
+
});
|
|
2912
|
+
|
|
2913
|
+
tempRl.question(
|
|
2914
|
+
'Masukkan nomor WhatsApp (contoh 628123456789): ',
|
|
2915
|
+
answer => {
|
|
2916
|
+
tempRl.close();
|
|
2917
|
+
rl.resume();
|
|
2918
|
+
resolve(answer);
|
|
2919
|
+
}
|
|
2920
|
+
);
|
|
2921
|
+
});
|
|
2922
|
+
|
|
2923
|
+
const number = phone.replace(/\D/g, '');
|
|
2924
|
+
|
|
2925
|
+
if (!number) {
|
|
2926
|
+
warn('Nomor tidak valid.');
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
try {
|
|
2931
|
+
info('Menunggu socket siap...');
|
|
2932
|
+
|
|
2933
|
+
await new Promise(resolve =>
|
|
2934
|
+
setTimeout(resolve, 6000)
|
|
2935
|
+
);
|
|
2936
|
+
|
|
2937
|
+
info('Meminta pairing code...');
|
|
2938
|
+
|
|
2939
|
+
const customCode = 'VINZZOFC';
|
|
2940
|
+
|
|
2941
|
+
const code =
|
|
2942
|
+
await sock.requestPairingCode(
|
|
2943
|
+
number,
|
|
2944
|
+
customCode
|
|
2945
|
+
);
|
|
2946
|
+
|
|
2947
|
+
console.log('');
|
|
2948
|
+
console.log(
|
|
2949
|
+
`🔑 PAIRING CODE: ${code}`
|
|
2950
|
+
);
|
|
2951
|
+
console.log('');
|
|
2952
|
+
info('Masukkan pairing code tersebut di WhatsApp.');
|
|
2953
|
+
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
errlog(
|
|
2956
|
+
'Gagal meminta pairing code',
|
|
2957
|
+
error
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
// --------------------------------------------------------
|
|
2963
|
+
// CREDENTIALS
|
|
2964
|
+
// --------------------------------------------------------
|
|
2965
|
+
|
|
2966
|
+
sock.ev.on(
|
|
2967
|
+
'creds.update',
|
|
2968
|
+
async creds => {
|
|
2969
|
+
|
|
2970
|
+
try {
|
|
2971
|
+
|
|
2972
|
+
debug(
|
|
2973
|
+
'creds.update'
|
|
2974
|
+
);
|
|
2975
|
+
|
|
2976
|
+
// Untuk state auth yang digunakan socket,
|
|
2977
|
+
// Baileys sudah memutasi authState.creds.
|
|
2978
|
+
await saveCreds(
|
|
2979
|
+
creds
|
|
2980
|
+
);
|
|
2981
|
+
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
|
|
2984
|
+
errlog(
|
|
2985
|
+
'Gagal menyimpan credentials',
|
|
2986
|
+
error
|
|
2987
|
+
);
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
);
|
|
2991
|
+
|
|
2992
|
+
// --------------------------------------------------------
|
|
2993
|
+
// CONNECTION UPDATE
|
|
2994
|
+
// --------------------------------------------------------
|
|
2995
|
+
|
|
2996
|
+
sock.ev.on(
|
|
2997
|
+
'connection.update',
|
|
2998
|
+
async update => {
|
|
2999
|
+
|
|
3000
|
+
lastConnectionUpdate =
|
|
3001
|
+
update;
|
|
3002
|
+
|
|
3003
|
+
debug(
|
|
3004
|
+
'connection.update',
|
|
3005
|
+
update
|
|
3006
|
+
);
|
|
3007
|
+
|
|
3008
|
+
const {
|
|
3009
|
+
connection,
|
|
3010
|
+
lastDisconnect,
|
|
3011
|
+
qr,
|
|
3012
|
+
isNewLogin,
|
|
3013
|
+
receivedPendingNotifications
|
|
3014
|
+
} = update;
|
|
3015
|
+
|
|
3016
|
+
if (
|
|
3017
|
+
connection
|
|
3018
|
+
) {
|
|
3019
|
+
connectionState =
|
|
3020
|
+
connection;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
// ----------------------------
|
|
3024
|
+
// QR
|
|
3025
|
+
// ----------------------------
|
|
3026
|
+
|
|
3027
|
+
if (qr) {
|
|
3028
|
+
|
|
3029
|
+
if (loginMethod === 'qr') {
|
|
3030
|
+
|
|
3031
|
+
console.log('');
|
|
3032
|
+
console.log(
|
|
3033
|
+
'\x1b[33m📱 Scan QR WhatsApp ini:\x1b[0m'
|
|
3034
|
+
);
|
|
3035
|
+
|
|
3036
|
+
await renderQR(qr);
|
|
3037
|
+
|
|
3038
|
+
} else {
|
|
3039
|
+
|
|
3040
|
+
debug(
|
|
3041
|
+
'QR diabaikan karena login method Pairing Code'
|
|
3042
|
+
);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
// ----------------------------
|
|
3047
|
+
// CONNECTING
|
|
3048
|
+
// ----------------------------
|
|
3049
|
+
|
|
3050
|
+
if (
|
|
3051
|
+
connection ===
|
|
3052
|
+
'connecting'
|
|
3053
|
+
) {
|
|
3054
|
+
|
|
3055
|
+
warn(
|
|
3056
|
+
'Sedang menghubungkan...'
|
|
3057
|
+
);
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// ----------------------------
|
|
3061
|
+
// OPEN
|
|
3062
|
+
// ----------------------------
|
|
3063
|
+
|
|
3064
|
+
if (
|
|
3065
|
+
connection ===
|
|
3066
|
+
'open'
|
|
3067
|
+
) {
|
|
3068
|
+
|
|
3069
|
+
reconnectAttempts =
|
|
3070
|
+
0;
|
|
3071
|
+
|
|
3072
|
+
connectionState =
|
|
3073
|
+
'open';
|
|
3074
|
+
|
|
3075
|
+
lastDisconnectInfo =
|
|
3076
|
+
null;
|
|
3077
|
+
|
|
3078
|
+
info(
|
|
3079
|
+
'BERHASIL TERHUBUNG KE WHATSAPP!'
|
|
3080
|
+
);
|
|
3081
|
+
|
|
3082
|
+
console.log('');
|
|
3083
|
+
|
|
3084
|
+
if (
|
|
3085
|
+
sock?.user
|
|
3086
|
+
) {
|
|
3087
|
+
|
|
3088
|
+
info(
|
|
3089
|
+
`Account: ${
|
|
3090
|
+
sock.user.id ??
|
|
3091
|
+
'-'
|
|
3092
|
+
}`
|
|
3093
|
+
);
|
|
3094
|
+
|
|
3095
|
+
if (
|
|
3096
|
+
sock.user.name
|
|
3097
|
+
) {
|
|
3098
|
+
info(
|
|
3099
|
+
`Name: ${
|
|
3100
|
+
sock.user.name
|
|
3101
|
+
}`
|
|
3102
|
+
);
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
debug(
|
|
3107
|
+
'Pending notifications',
|
|
3108
|
+
receivedPendingNotifications
|
|
3109
|
+
);
|
|
3110
|
+
|
|
3111
|
+
prompt();
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
// ----------------------------
|
|
3115
|
+
// CLOSE
|
|
3116
|
+
// ----------------------------
|
|
3117
|
+
|
|
3118
|
+
if (
|
|
3119
|
+
connection ===
|
|
3120
|
+
'close'
|
|
3121
|
+
) {
|
|
3122
|
+
|
|
3123
|
+
const disconnect =
|
|
3124
|
+
parseDisconnect(
|
|
3125
|
+
lastDisconnect
|
|
3126
|
+
);
|
|
3127
|
+
|
|
3128
|
+
lastDisconnectInfo =
|
|
3129
|
+
disconnect;
|
|
3130
|
+
|
|
3131
|
+
connectionState =
|
|
3132
|
+
'closed';
|
|
3133
|
+
|
|
3134
|
+
terminalStarted =
|
|
3135
|
+
false;
|
|
3136
|
+
|
|
3137
|
+
console.log('');
|
|
3138
|
+
console.log(
|
|
3139
|
+
'\x1b[31m========== CONNECTION CLOSED ==========\x1b[0m'
|
|
3140
|
+
);
|
|
3141
|
+
|
|
3142
|
+
debug(
|
|
3143
|
+
'Disconnect info',
|
|
3144
|
+
disconnect
|
|
3145
|
+
);
|
|
3146
|
+
|
|
3147
|
+
warn(
|
|
3148
|
+
`Disconnect: ${
|
|
3149
|
+
disconnect.message
|
|
3150
|
+
}`
|
|
3151
|
+
);
|
|
3152
|
+
|
|
3153
|
+
if (
|
|
3154
|
+
disconnect.statusCode !==
|
|
3155
|
+
null
|
|
3156
|
+
) {
|
|
3157
|
+
warn(
|
|
3158
|
+
`Status code: ${
|
|
3159
|
+
disconnect.statusCode
|
|
3160
|
+
}`
|
|
3161
|
+
);
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
if (
|
|
3165
|
+
disconnect.reason
|
|
3166
|
+
) {
|
|
3167
|
+
warn(
|
|
3168
|
+
`Reason: ${
|
|
3169
|
+
disconnect.reason
|
|
3170
|
+
}`
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
if (
|
|
3175
|
+
disconnect.location
|
|
3176
|
+
) {
|
|
3177
|
+
warn(
|
|
3178
|
+
`Location: ${
|
|
3179
|
+
disconnect.location
|
|
3180
|
+
}`
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
// Tutup DB handle kalau SQLite
|
|
3185
|
+
try {
|
|
3186
|
+
closeAuth?.();
|
|
3187
|
+
} catch {}
|
|
3188
|
+
|
|
3189
|
+
sock =
|
|
3190
|
+
null;
|
|
3191
|
+
|
|
3192
|
+
if (!shuttingDown) {
|
|
3193
|
+
if (disconnect.statusCode === 401) {
|
|
3194
|
+
warn('Login ditolak / session tidak valid.');
|
|
3195
|
+
warn('Hapus session lalu jalankan ulang.');
|
|
3196
|
+
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
scheduleReconnect();
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
);
|
|
3205
|
+
|
|
3206
|
+
// --------------------------------------------------------
|
|
3207
|
+
// INCOMING MESSAGES
|
|
3208
|
+
// --------------------------------------------------------
|
|
3209
|
+
|
|
3210
|
+
sock.ev.on(
|
|
3211
|
+
'messages.upsert',
|
|
3212
|
+
async ({ messages, type }) => {
|
|
3213
|
+
|
|
3214
|
+
if (!Array.isArray(messages)) {
|
|
3215
|
+
return;
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
for (
|
|
3219
|
+
const message
|
|
3220
|
+
of messages
|
|
3221
|
+
) {
|
|
3222
|
+
|
|
3223
|
+
if (!message) {
|
|
3224
|
+
continue;
|
|
3225
|
+
}
|
|
3226
|
+
saveMessage(message);
|
|
3227
|
+
const key =
|
|
3228
|
+
message.key;
|
|
3229
|
+
|
|
3230
|
+
const remoteJid =
|
|
3231
|
+
key?.remoteJid ??
|
|
3232
|
+
null;
|
|
3233
|
+
|
|
3234
|
+
const sender =
|
|
3235
|
+
key?.participant ??
|
|
3236
|
+
remoteJid ??
|
|
3237
|
+
null;
|
|
3238
|
+
|
|
3239
|
+
const fromMe =
|
|
3240
|
+
key?.fromMe === true;
|
|
3241
|
+
|
|
3242
|
+
const isGroup =
|
|
3243
|
+
typeof remoteJid ===
|
|
3244
|
+
'string' &&
|
|
3245
|
+
remoteJid.endsWith(
|
|
3246
|
+
'@g.us'
|
|
3247
|
+
);
|
|
3248
|
+
|
|
3249
|
+
const status =
|
|
3250
|
+
isGroup
|
|
3251
|
+
? 'GROUP'
|
|
3252
|
+
: 'PRIVATE';
|
|
3253
|
+
|
|
3254
|
+
const text =
|
|
3255
|
+
extractMessageText(
|
|
3256
|
+
message.message
|
|
3257
|
+
) ||
|
|
3258
|
+
null;
|
|
3259
|
+
|
|
3260
|
+
const messageType =
|
|
3261
|
+
getMessageType(
|
|
3262
|
+
message.message
|
|
3263
|
+
) ??
|
|
3264
|
+
'unknown';
|
|
3265
|
+
|
|
3266
|
+
const senderName =
|
|
3267
|
+
message.pushName ??
|
|
3268
|
+
null;
|
|
3269
|
+
|
|
3270
|
+
let groupName =
|
|
3271
|
+
null;
|
|
3272
|
+
|
|
3273
|
+
// Ambil nama grup kalau pesan dari grup
|
|
3274
|
+
if (isGroup) {
|
|
3275
|
+
|
|
3276
|
+
try {
|
|
3277
|
+
|
|
3278
|
+
const metadata =
|
|
3279
|
+
await sock.groupMetadata(
|
|
3280
|
+
remoteJid
|
|
3281
|
+
);
|
|
3282
|
+
|
|
3283
|
+
groupName =
|
|
3284
|
+
metadata?.subject ??
|
|
3285
|
+
null;
|
|
3286
|
+
|
|
3287
|
+
} catch {
|
|
3288
|
+
|
|
3289
|
+
groupName =
|
|
3290
|
+
null;
|
|
3291
|
+
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
// Jangan tampilkan message kosong
|
|
3296
|
+
if (
|
|
3297
|
+
!message.message
|
|
3298
|
+
) {
|
|
3299
|
+
continue;
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
messageCount++;
|
|
3303
|
+
|
|
3304
|
+
console.log('');
|
|
3305
|
+
console.log(
|
|
3306
|
+
'\x1b[35m╔══════════════════════════════════════════════════╗\x1b[0m'
|
|
3307
|
+
);
|
|
3308
|
+
|
|
3309
|
+
console.log(
|
|
3310
|
+
'\x1b[35m║ 📩 PESAN MASUK BARU ║\x1b[0m'
|
|
3311
|
+
);
|
|
3312
|
+
|
|
3313
|
+
console.log(
|
|
3314
|
+
'\x1b[35m╚══════════════════════════════════════════════════╝\x1b[0m'
|
|
3315
|
+
);
|
|
3316
|
+
|
|
3317
|
+
console.log('');
|
|
3318
|
+
|
|
3319
|
+
console.log(
|
|
3320
|
+
`📌 STATUS : ${
|
|
3321
|
+
status
|
|
3322
|
+
}`
|
|
3323
|
+
);
|
|
3324
|
+
|
|
3325
|
+
console.log(
|
|
3326
|
+
`📨 EVENT : ${
|
|
3327
|
+
type ??
|
|
3328
|
+
'unknown'
|
|
3329
|
+
}`
|
|
3330
|
+
);
|
|
3331
|
+
|
|
3332
|
+
console.log(
|
|
3333
|
+
`👤 PENGIRIM : ${
|
|
3334
|
+
sender ??
|
|
3335
|
+
'null'
|
|
3336
|
+
}`
|
|
3337
|
+
);
|
|
3338
|
+
|
|
3339
|
+
console.log(
|
|
3340
|
+
`📛 NAMA : ${
|
|
3341
|
+
senderName ??
|
|
3342
|
+
'null'
|
|
3343
|
+
}`
|
|
3344
|
+
);
|
|
3345
|
+
|
|
3346
|
+
console.log(
|
|
3347
|
+
`💬 CHAT : ${
|
|
3348
|
+
remoteJid ??
|
|
3349
|
+
'null'
|
|
3350
|
+
}`
|
|
3351
|
+
);
|
|
3352
|
+
|
|
3353
|
+
console.log(
|
|
3354
|
+
`👥 GRUP : ${
|
|
3355
|
+
groupName ??
|
|
3356
|
+
'null'
|
|
3357
|
+
}`
|
|
3358
|
+
);
|
|
3359
|
+
|
|
3360
|
+
console.log(
|
|
3361
|
+
`📦 JENIS PESAN : ${
|
|
3362
|
+
messageType
|
|
3363
|
+
}`
|
|
3364
|
+
);
|
|
3365
|
+
|
|
3366
|
+
console.log(
|
|
3367
|
+
`↩️ DARI SAYA : ${
|
|
3368
|
+
fromMe
|
|
3369
|
+
}`
|
|
3370
|
+
);
|
|
3371
|
+
|
|
3372
|
+
console.log('');
|
|
3373
|
+
|
|
3374
|
+
console.log(
|
|
3375
|
+
'📝 ISI PESAN'
|
|
3376
|
+
);
|
|
3377
|
+
|
|
3378
|
+
console.log(
|
|
3379
|
+
'──────────────────────────────────────────────────'
|
|
3380
|
+
);
|
|
3381
|
+
|
|
3382
|
+
console.log(
|
|
3383
|
+
text ??
|
|
3384
|
+
'[Tidak ada teks]'
|
|
3385
|
+
);
|
|
3386
|
+
|
|
3387
|
+
console.log(
|
|
3388
|
+
'──────────────────────────────────────────────────'
|
|
3389
|
+
);
|
|
3390
|
+
|
|
3391
|
+
console.log('');
|
|
3392
|
+
|
|
3393
|
+
console.log(
|
|
3394
|
+
`🆔 MESSAGE ID : ${
|
|
3395
|
+
key?.id ??
|
|
3396
|
+
'null'
|
|
3397
|
+
}`
|
|
3398
|
+
);
|
|
3399
|
+
|
|
3400
|
+
console.log(
|
|
3401
|
+
`🕒 WAKTU : ${
|
|
3402
|
+
message.messageTimestamp
|
|
3403
|
+
? new Date(
|
|
3404
|
+
Number(
|
|
3405
|
+
message.messageTimestamp
|
|
3406
|
+
) * 1000
|
|
3407
|
+
).toISOString()
|
|
3408
|
+
: 'null'
|
|
3409
|
+
}`
|
|
3410
|
+
);
|
|
3411
|
+
|
|
3412
|
+
console.log('');
|
|
3413
|
+
|
|
3414
|
+
console.log(
|
|
3415
|
+
'\x1b[35m════════════════════════════════════════════════════\x1b[0m'
|
|
3416
|
+
);
|
|
3417
|
+
|
|
3418
|
+
console.log('');
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
);
|
|
3422
|
+
|
|
3423
|
+
// --------------------------------------------------------
|
|
3424
|
+
// GROUP / PRESENCE DEBUG
|
|
3425
|
+
// --------------------------------------------------------
|
|
3426
|
+
|
|
3427
|
+
sock.ev.on(
|
|
3428
|
+
'presence.update',
|
|
3429
|
+
update => {
|
|
3430
|
+
debug(
|
|
3431
|
+
'presence.update',
|
|
3432
|
+
update
|
|
3433
|
+
);
|
|
3434
|
+
}
|
|
3435
|
+
);
|
|
3436
|
+
|
|
3437
|
+
if (
|
|
3438
|
+
typeof closeAuth ===
|
|
3439
|
+
'function'
|
|
3440
|
+
) {
|
|
3441
|
+
// closeAuth dikelola saat connection close
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
// ------------------------------------------------------------
|
|
3446
|
+
// Pino lazy logger
|
|
3447
|
+
// ------------------------------------------------------------
|
|
3448
|
+
|
|
3449
|
+
function pinoLogger() {
|
|
3450
|
+
|
|
3451
|
+
// Import synchronous sudah tersedia lewat dynamic import?
|
|
3452
|
+
// Pino belum di-import di atas supaya script fleksibel.
|
|
3453
|
+
// Gunakan require tidak bisa pada ESM, jadi ambil dari cache
|
|
3454
|
+
// menggunakan createRequire.
|
|
3455
|
+
return loggerInstance;
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
let loggerInstance;
|
|
3459
|
+
|
|
3460
|
+
{
|
|
3461
|
+
const {
|
|
3462
|
+
createRequire
|
|
3463
|
+
} = await import(
|
|
3464
|
+
'module'
|
|
3465
|
+
);
|
|
3466
|
+
|
|
3467
|
+
const require =
|
|
3468
|
+
createRequire(
|
|
3469
|
+
import.meta.url
|
|
3470
|
+
);
|
|
3471
|
+
|
|
3472
|
+
const pino =
|
|
3473
|
+
require('pino');
|
|
3474
|
+
|
|
3475
|
+
loggerInstance =
|
|
3476
|
+
pino({
|
|
3477
|
+
level: LOG_LEVEL
|
|
3478
|
+
});
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
// ------------------------------------------------------------
|
|
3482
|
+
// SHUTDOWN
|
|
3483
|
+
// ------------------------------------------------------------
|
|
3484
|
+
|
|
3485
|
+
async function shutdown() {
|
|
3486
|
+
|
|
3487
|
+
if (
|
|
3488
|
+
shuttingDown
|
|
3489
|
+
) {
|
|
3490
|
+
return;
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
shuttingDown =
|
|
3494
|
+
true;
|
|
3495
|
+
|
|
3496
|
+
console.log('');
|
|
3497
|
+
warn(
|
|
3498
|
+
'Shutdown dimulai...'
|
|
3499
|
+
);
|
|
3500
|
+
|
|
3501
|
+
if (
|
|
3502
|
+
reconnectTimer
|
|
3503
|
+
) {
|
|
3504
|
+
clearTimeout(
|
|
3505
|
+
reconnectTimer
|
|
3506
|
+
);
|
|
3507
|
+
|
|
3508
|
+
reconnectTimer =
|
|
3509
|
+
null;
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
try {
|
|
3513
|
+
if (sock) {
|
|
3514
|
+
sock.end();
|
|
3515
|
+
}
|
|
3516
|
+
} catch {}
|
|
3517
|
+
|
|
3518
|
+
try {
|
|
3519
|
+
rl.close();
|
|
3520
|
+
} catch {}
|
|
3521
|
+
|
|
3522
|
+
info(
|
|
3523
|
+
'Bot dihentikan.'
|
|
3524
|
+
);
|
|
3525
|
+
|
|
3526
|
+
process.exit(0);
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
// ------------------------------------------------------------
|
|
3530
|
+
// GLOBAL ERRORS
|
|
3531
|
+
// ------------------------------------------------------------
|
|
3532
|
+
|
|
3533
|
+
process.on(
|
|
3534
|
+
'uncaughtException',
|
|
3535
|
+
error => {
|
|
3536
|
+
|
|
3537
|
+
errlog(
|
|
3538
|
+
'UNCAUGHT EXCEPTION',
|
|
3539
|
+
error
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
);
|
|
3543
|
+
|
|
3544
|
+
process.on(
|
|
3545
|
+
'unhandledRejection',
|
|
3546
|
+
reason => {
|
|
3547
|
+
|
|
3548
|
+
errlog(
|
|
3549
|
+
'UNHANDLED REJECTION',
|
|
3550
|
+
reason
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
);
|
|
3554
|
+
|
|
3555
|
+
process.on(
|
|
3556
|
+
'SIGINT',
|
|
3557
|
+
async () => {
|
|
3558
|
+
await shutdown();
|
|
3559
|
+
}
|
|
3560
|
+
);
|
|
3561
|
+
|
|
3562
|
+
process.on(
|
|
3563
|
+
'SIGTERM',
|
|
3564
|
+
async () => {
|
|
3565
|
+
await shutdown();
|
|
3566
|
+
}
|
|
3567
|
+
);
|
|
3568
|
+
|
|
3569
|
+
// ------------------------------------------------------------
|
|
3570
|
+
// START
|
|
3571
|
+
// ------------------------------------------------------------
|
|
3572
|
+
|
|
3573
|
+
console.clear();
|
|
3574
|
+
|
|
3575
|
+
console.log(
|
|
3576
|
+
'\x1b[36m=========================================='
|
|
3577
|
+
);
|
|
3578
|
+
|
|
3579
|
+
console.log(
|
|
3580
|
+
' SMART WHATSAPP CLI'
|
|
3581
|
+
);
|
|
3582
|
+
|
|
3583
|
+
console.log(
|
|
3584
|
+
'==========================================\x1b[0m'
|
|
3585
|
+
);
|
|
3586
|
+
|
|
3587
|
+
console.log('');
|
|
3588
|
+
|
|
3589
|
+
let ACTIVE_SESSION_DIR = null;
|
|
3590
|
+
|
|
3591
|
+
async function startApp() {
|
|
3592
|
+
console.clear();
|
|
3593
|
+
console.log('\x1b[36m==========================================');
|
|
3594
|
+
console.log(' SMART WHATSAPP CLI');
|
|
3595
|
+
console.log('==========================================\x1b[0m\n');
|
|
3596
|
+
|
|
3597
|
+
// 1. Pilih session saat readline CLI belum aktif (Joystick/Panah Lancar)
|
|
3598
|
+
ACTIVE_SESSION_DIR = await selectOrCreateSession();
|
|
3599
|
+
|
|
3600
|
+
// 2. Inisialisasi Readline & Prompt HIJAU setelah selection selesai
|
|
3601
|
+
initReadline();
|
|
3602
|
+
|
|
3603
|
+
info(`Session aktif: ${path.basename(ACTIVE_SESSION_DIR)}`);
|
|
3604
|
+
console.log('');
|
|
3605
|
+
|
|
3606
|
+
// 3. Connect ke WhatsApp
|
|
3607
|
+
await connectWhatsApp(ACTIVE_SESSION_DIR);
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
startApp();
|
|
3611
|
+
|