@manybot/manybot 5.5.4 → 5.6.1

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.
Files changed (40) hide show
  1. package/README.md +15 -1
  2. package/dist/client/cache.js +1 -1
  3. package/dist/client/store.js +9 -0
  4. package/dist/config.js +230 -12
  5. package/dist/drivers/baileys/adapter.js +629 -0
  6. package/dist/drivers/{whatsapp → baileys}/api/index.js +553 -393
  7. package/dist/drivers/baileys/index.js +594 -0
  8. package/dist/drivers/{whatsapp → baileys}/loginPrompt.js +2 -0
  9. package/dist/drivers/{whatsapp → baileys}/messageHandler.js +46 -16
  10. package/dist/drivers/{whatsapp → baileys}/sdk/baileysSock.js +1 -30
  11. package/dist/drivers/jid.js +31 -0
  12. package/dist/drivers/types.js +14 -0
  13. package/dist/drivers/whatsmeow/client.js +252 -0
  14. package/dist/drivers/whatsmeow/index.js +79 -0
  15. package/dist/drivers/whatsmeow/installer.js +86 -0
  16. package/dist/drivers/whatsmeow/supervisor.js +328 -0
  17. package/dist/drivers/whatsmeow/whatsmeow.proto +64 -0
  18. package/dist/i18n/index.js +8 -12
  19. package/dist/kernel/alerts.js +190 -0
  20. package/dist/kernel/contactAutoSave.js +200 -0
  21. package/dist/kernel/driverManager.js +117 -0
  22. package/dist/kernel/pluginApi.js +25 -7
  23. package/dist/kernel/pluginLoader.js +12 -12
  24. package/dist/kernel/sendFallbackGuard.js +183 -0
  25. package/dist/kernel/sendGuard.js +143 -33
  26. package/dist/kernel/statusServer.js +39 -0
  27. package/dist/kernel/updateCheck.js +88 -0
  28. package/dist/kernel/waContract.js +16 -0
  29. package/dist/locales/en.json +16 -1
  30. package/dist/locales/es.json +16 -1
  31. package/dist/locales/pt.json +16 -1
  32. package/dist/main.js +100 -5
  33. package/dist/types.js +18 -11
  34. package/package.json +6 -8
  35. package/dist/core/adapter.js +0 -12
  36. package/dist/core/capabilities.js +0 -16
  37. package/dist/core/types.js +0 -6
  38. package/dist/drivers/index.js +0 -14
  39. package/dist/drivers/whatsapp/adapter.js +0 -7
  40. package/dist/drivers/whatsapp/index.js +0 -382
package/README.md CHANGED
@@ -17,10 +17,14 @@ Open-source framework for message automation, extensible via community plugins.
17
17
  ## Requirements
18
18
 
19
19
  - Node.js >= 24
20
- - npm
20
+ - npm >= 9
21
+ - Go >= 1.23 (for whatsmeow driver)
22
+ - protoc (for protobuf codegen)
21
23
 
22
24
  ## Getting started
23
25
 
26
+ ### Install from npm
27
+
24
28
  ```bash
25
29
  npm install -g @manybot/manybot
26
30
  npm install -g @manybot/manyplug
@@ -29,6 +33,16 @@ manybot
29
33
 
30
34
  On first run, a configuration file is created at `~/.manybot/manybot.toml`. Edit it to set up your preferences.
31
35
 
36
+ ### Develop from source
37
+
38
+ ```bash
39
+ git clone <repo-url>
40
+ cd dev
41
+ npm install
42
+ go build -o whatsmeow-service/bin/whatsmeow-service ./whatsmeow-service
43
+ npm start
44
+ ```
45
+
32
46
  For detailed setup instructions, see the **[documentation](https://manybot.org/docs/)**.
33
47
 
34
48
  ## Plugins
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Why: an already-linked WhatsApp session doesn't get a full history
7
7
  * resync on reconnect — only a partial, non-deterministic slice of it
8
- * (see drivers/whatsapp/index.ts). Each fresh process starts with an
8
+ * (see drivers/baileys/index.ts). Each fresh process starts with an
9
9
  * empty in-memory store, so without a cache, chats seen in a previous
10
10
  * run can silently disappear from the current one.
11
11
  *
@@ -8,6 +8,15 @@
8
8
  * - chat names (for display and for building WAChat adapters)
9
9
  * - contact names / notify (pushname) (for ctx.contacts)
10
10
  * - messages by JID + ID (for poll vote decryption)
11
+ *
12
+ * PR1 of the whatsmeow-fallback refactor (see AUDIT_BAILEYS_LEAK.md):
13
+ * this module no longer imports from `@whiskeysockets/baileys`. The
14
+ * Baileys-specific shapes (WAMessage, Chat, Contact) are re-exported
15
+ * from src/drivers/baileys/sdk/baileysSock.ts as the driver-local
16
+ * aliases RawMessage, RawChat, RawContact — the rest of the codebase
17
+ * (this module included) sees only those neutral names, so the
18
+ * @whiskeysockets/baileys import line never leaks past the driver
19
+ * boundary.
11
20
  */
12
21
  // ── Factory ───────────────────────────────────────────────────────────────────
13
22
  /**
package/dist/config.js CHANGED
@@ -198,32 +198,136 @@ function detectSystemLang() {
198
198
  const DEFAULT_TOML_EN = `# ManyBot configuration file
199
199
  # See https://manybot.org/docs/config to learn more
200
200
 
201
- CLIENT_ID = "manybot"
202
- CMD_PREFIX = "!"
203
- CHATS = []
204
- LANGUAGE = "en"
205
- PHONE_NUMBER = ""
201
+ CLIENT_ID = "manybot"
202
+ CMD_PREFIX = "!"
203
+ CHATS = []
204
+ EXCLUDE_CHATS = []
205
+ LANGUAGE = "en"
206
+ PHONE_NUMBER = ""
207
+
208
+ # How cautious the bot is about looking automated: "low", "medium", "high".
209
+ # Higher levels slow the bot down (fewer concurrent chats, longer delays)
210
+ # but reduce the risk of WhatsApp flagging the account.
211
+ SECURITY_LEVEL = "medium"
212
+
213
+ # ── Local alerts (critical warnings, update notices) ──────────────────────
214
+ # Phone number (or full JID) that receives WhatsApp alerts when the bot
215
+ # itself is up — e.g. "5511999999999" or "5511999999999@s.whatsapp.net".
216
+ # Leave blank to disable this sink (the log file and OS notification still
217
+ # work even if the bot is down or restricted).
218
+ ADMIN_JID = ""
219
+
220
+ # SMTP is optional — leave SMTP_HOST blank to disable the email sink.
221
+ # SMTP_SEC: "starttls" (port 587, upgrades after connecting — most
222
+ # providers), "ssl" (port 465, encrypted from the start), or "none".
223
+ SMTP_HOST = ""
224
+ SMTP_PORT = 587
225
+ SMTP_SEC = "starttls"
226
+ SMTP_USER = ""
227
+ SMTP_PASS = ""
228
+ SMTP_FROM = ""
229
+ SMTP_TO = ""
230
+ # Skip TLS certificate validation. Needed for local SMTP proxies with a
231
+ # self-signed cert — e.g. Proton Mail Bridge (127.0.0.1), Mailhog,
232
+ # Mailpit. Leave false for a real remote mail provider.
233
+ SMTP_INSECURE = false
234
+
235
+ # Checks npm for a newer manybot version: on startup, then every
236
+ # UPDATE_CHECK_INTERVAL_HOURS.
237
+ UPDATE_CHECK_ENABLED = true
238
+ UPDATE_CHECK_INTERVAL_HOURS = 24
206
239
 
207
240
  # How to connect the first time: "qr" (scan with WhatsApp on your phone)
208
241
  # or "phone" (receive a pairing code on the number set in PHONE_NUMBER).
209
242
  # Leave blank to choose interactively on first run — the choice is then
210
243
  # saved here automatically.
211
244
  LOGIN_METHOD = ""
245
+
246
+ # ── Status page ────────────────────────────────────────────────────────────
247
+ # Local HTTP page showing whether the bot is online or offline.
248
+ STATUS_ENABLED = true
249
+ STATUS_PORT = 8080
250
+
251
+ # ── Driver selection (advanced) ────────────────────────────────────────────
252
+ # ManyBot can fall back from a primary driver to a secondary one when the
253
+ # primary fails to confirm a send. Today only Baileys is wired in; leave
254
+ # driver_whatsmeow_enabled = false to disable the fallback entirely (no
255
+ # extra processes are spawned, no sockets are opened).
256
+ driver_primary = "baileys"
257
+ driver_fallback_cooldown_ms = 60000
258
+ driver_verify_window_ms = [500, 1000, 1500, 2500, 5000]
259
+ driver_baileys_enabled = true
260
+ driver_whatsmeow_enabled = false
261
+ driver_whatsmeow_grpc_address = "localhost:50051"
262
+ driver_whatsmeow_binary_path = ""
212
263
  `;
213
264
  const DEFAULT_TOML_PT = `# Arquivo de configuração do ManyBot
214
265
  # Veja https://manybot.org/docs/config para saber mais
215
266
 
216
- CLIENT_ID = "manybot"
217
- CMD_PREFIX = "!"
218
- CHATS = []
219
- LANGUAGE = "pt"
220
- PHONE_NUMBER = ""
267
+ CLIENT_ID = "manybot"
268
+ CMD_PREFIX = "!"
269
+ CHATS = []
270
+ EXCLUDE_CHATS = []
271
+ LANGUAGE = "pt"
272
+ PHONE_NUMBER = ""
273
+
274
+ # Quão cauteloso o bot é pra não parecer automatizado: "low", "medium", "high".
275
+ # Níveis mais altos deixam o bot mais lento (menos chats simultâneos, atrasos
276
+ # maiores), mas reduzem o risco do WhatsApp sinalizar a conta.
277
+ SECURITY_LEVEL = "medium"
278
+
279
+ # ── Avisos locais (alertas críticos, aviso de update) ──────────────────────
280
+ # Número de telefone (ou JID completo) que recebe alertas via WhatsApp
281
+ # quando o bot está de pé — ex. "5511999999999" ou
282
+ # "5511999999999@s.whatsapp.net". Deixe em branco pra desligar esse canal
283
+ # (o log e a notificação do SO continuam funcionando mesmo com o bot
284
+ # caído ou restrito).
285
+ ADMIN_JID = ""
286
+
287
+ # SMTP é opcional — deixe SMTP_HOST em branco pra desligar o canal de e-mail.
288
+ # SMTP_SEC: "starttls" (porta 587, atualiza a conexão depois de
289
+ # conectar — maioria dos provedores), "ssl" (porta 465, criptografado
290
+ # desde o início), ou "none".
291
+ SMTP_HOST = ""
292
+ SMTP_PORT = 587
293
+ SMTP_SEC = "starttls"
294
+ SMTP_USER = ""
295
+ SMTP_PASS = ""
296
+ SMTP_FROM = ""
297
+ SMTP_TO = ""
298
+ # Pula a validação do certificado TLS. Necessário pra proxies SMTP
299
+ # locais com certificado autoassinado — ex. Proton Mail Bridge
300
+ # (127.0.0.1), Mailhog, Mailpit. Deixe false pra um provedor remoto real.
301
+ SMTP_INSECURE = false
302
+
303
+ # Checa no npm se tem versão nova do manybot: ao iniciar, e depois a cada
304
+ # UPDATE_CHECK_INTERVAL_HOURS.
305
+ UPDATE_CHECK_ENABLED = true
306
+ UPDATE_CHECK_INTERVAL_HOURS = 24
221
307
 
222
308
  # Como conectar pela primeira vez: "qr" (escaneie com o WhatsApp no celular)
223
309
  # ou "phone" (recebe um código de pareamento no número definido em
224
310
  # PHONE_NUMBER). Deixe em branco para escolher interativamente na primeira
225
311
  # execução — a escolha é salva aqui automaticamente.
226
312
  LOGIN_METHOD = ""
313
+
314
+ # ── Página de status ────────────────────────────────────────────────────────
315
+ # Página HTTP local mostrando se o bot está online ou offline.
316
+ STATUS_ENABLED = true
317
+ STATUS_PORT = 8080
318
+
319
+ # ── Seleção de driver (avançado) ───────────────────────────────────────────
320
+ # ManyBot pode cair de um driver primário pra um secundário quando o
321
+ # primário não confirma um envio. Hoje só Baileys está ligado; deixe
322
+ # driver_whatsmeow_enabled = false pra desligar o fallback por completo
323
+ # (nenhum processo extra é spawnado, nenhum socket é aberto).
324
+ driver_primary = "baileys"
325
+ driver_fallback_cooldown_ms = 60000
326
+ driver_verify_window_ms = [500, 1000, 1500, 2500, 5000]
327
+ driver_baileys_enabled = true
328
+ driver_whatsmeow_enabled = false
329
+ driver_whatsmeow_grpc_address = "localhost:50051"
330
+ driver_whatsmeow_binary_path = ""
227
331
  `;
228
332
  const DEFAULT_TOML = detectSystemLang() === "pt" ? DEFAULT_TOML_PT : DEFAULT_TOML_EN;
229
333
  await fs.mkdir(CONFIG_DIR, { recursive: true });
@@ -262,11 +366,32 @@ const DEFAULTS = {
262
366
  CMD_PREFIX: "!",
263
367
  CLIENT_ID: "manybot",
264
368
  CHATS: [],
369
+ EXCLUDE_CHATS: [],
370
+ SECURITY_LEVEL: "medium",
265
371
  PLUGINS: [],
266
372
  LANGUAGE: "en",
267
373
  PHONE_NUMBER: null,
268
- PLATFORM: "whatsapp",
269
374
  LOGIN_METHOD: null,
375
+ ADMIN_JID: "",
376
+ SMTP_HOST: "",
377
+ SMTP_PORT: 587,
378
+ SMTP_SEC: "starttls",
379
+ SMTP_USER: "",
380
+ SMTP_PASS: "",
381
+ SMTP_FROM: "",
382
+ SMTP_TO: "",
383
+ SMTP_INSECURE: false,
384
+ UPDATE_CHECK_ENABLED: true,
385
+ UPDATE_CHECK_INTERVAL_HOURS: 24,
386
+ STATUS_ENABLED: true,
387
+ STATUS_PORT: 8080,
388
+ drivers: {
389
+ primary: "baileys",
390
+ fallbackCooldownMs: 60000,
391
+ verifyWindowMs: [500, 1000, 1500, 2500, 5000],
392
+ baileys: { enabled: true },
393
+ whatsmeow: { enabled: false, grpcAddress: "localhost:50051", binaryPath: "" },
394
+ },
270
395
  };
271
396
  function normalize(cfg) {
272
397
  // Empty string and absent PHONE_NUMBER are both treated as null so plugins
@@ -279,6 +404,83 @@ function normalize(cfg) {
279
404
  if (cfg.LOGIN_METHOD !== "phone" && cfg.LOGIN_METHOD !== "qr") {
280
405
  cfg.LOGIN_METHOD = null;
281
406
  }
407
+ if (!["low", "medium", "high"].includes(cfg.SECURITY_LEVEL)) {
408
+ cfg.SECURITY_LEVEL = "medium";
409
+ }
410
+ // Legacy .conf values arrive as strings; TOML gives real types already —
411
+ // Number()/coercion here is a no-op for the TOML path.
412
+ cfg.SMTP_PORT = Number(cfg.SMTP_PORT) || 587;
413
+ if (!["starttls", "ssl", "none"].includes(cfg.SMTP_SEC)) {
414
+ cfg.SMTP_SEC = "starttls";
415
+ }
416
+ const rawUpdateEnabled = cfg.UPDATE_CHECK_ENABLED;
417
+ cfg.UPDATE_CHECK_ENABLED = rawUpdateEnabled !== false && rawUpdateEnabled !== "false";
418
+ const rawSmtpInsecure = cfg.SMTP_INSECURE;
419
+ cfg.SMTP_INSECURE = rawSmtpInsecure === true || rawSmtpInsecure === "true";
420
+ cfg.UPDATE_CHECK_INTERVAL_HOURS = Number(cfg.UPDATE_CHECK_INTERVAL_HOURS) || 24;
421
+ const rawStatusEnabled = cfg.STATUS_ENABLED;
422
+ cfg.STATUS_ENABLED = rawStatusEnabled !== false && rawStatusEnabled !== "false";
423
+ cfg.STATUS_PORT = Number(cfg.STATUS_PORT) || 8080;
424
+ // drivers.* — the fallback guard and DriverManager read these at every
425
+ // send. The TOML surface is flat lowercase keys (driver_primary,
426
+ // driver_baileys_enabled, driver_whatsmeow_*, …) so it matches the
427
+ // rest of the file; the nested `cfg.drivers` object is rebuilt here
428
+ // from those flat keys so callers (main.ts, sendFallbackGuard.ts,
429
+ // supervisor.ts, client.ts) keep using `CONFIG.drivers.*`.
430
+ // Coerce strings (legacy .conf arrives as strings) and reject anything
431
+ // that isn't a recognized driver name, so a typo in TOML falls back
432
+ // to the safe default rather than crashing at boot.
433
+ const isTruthy = (v) => v === true || v === "true";
434
+ const coerceEnabled = (v, fallback) => {
435
+ if (v === true || v === false)
436
+ return v;
437
+ if (v === "true")
438
+ return true;
439
+ if (v === "false")
440
+ return false;
441
+ return fallback;
442
+ };
443
+ // Allow either the new flat keys or (for backward compatibility) the
444
+ // old nested `[drivers]` block. Flat keys take precedence.
445
+ const nestedDrv = (cfg.drivers ?? {});
446
+ const flatPrimary = cfg.driver_primary ?? nestedDrv.primary;
447
+ const flatCooldown = cfg.driver_fallback_cooldown_ms ?? nestedDrv.fallbackCooldownMs;
448
+ const flatVerify = cfg.driver_verify_window_ms ?? nestedDrv.verifyWindowMs;
449
+ const flatBaileysEnabled = cfg.driver_baileys_enabled ?? nestedDrv.baileys?.enabled;
450
+ const flatWhatsmeowEnabled = cfg.driver_whatsmeow_enabled ?? nestedDrv.whatsmeow?.enabled;
451
+ const flatWhatsmeowGrpc = cfg.driver_whatsmeow_grpc_address ?? nestedDrv.whatsmeow?.grpcAddress;
452
+ const flatWhatsmeowBinary = cfg.driver_whatsmeow_binary_path ?? nestedDrv.whatsmeow?.binaryPath;
453
+ cfg.drivers = {
454
+ primary: flatPrimary === "whatsmeow" ? "whatsmeow" : "baileys",
455
+ fallbackCooldownMs: Number(flatCooldown) || 60000,
456
+ verifyWindowMs: Array.isArray(flatVerify) && flatVerify.length
457
+ ? flatVerify.map((n) => Number(n)).filter((n) => Number.isFinite(n) && n > 0)
458
+ : [500, 1000, 1500, 2500, 5000],
459
+ baileys: {
460
+ enabled: coerceEnabled(flatBaileysEnabled, true),
461
+ },
462
+ whatsmeow: {
463
+ // MANYBOT_SMOKE=1 force-enables whatsmeow regardless of the TOML
464
+ // value — used by scripts/smoke-whatsmeow-supervisor.mjs so the
465
+ // smoke test doesn't depend on the local manybot.toml already
466
+ // having driver_whatsmeow_enabled = true. Not a documented
467
+ // user-facing setting; TOML remains the source of truth outside
468
+ // smoke runs.
469
+ enabled: process.env.MANYBOT_SMOKE === "1" ? true : isTruthy(flatWhatsmeowEnabled),
470
+ grpcAddress: typeof flatWhatsmeowGrpc === "string" ? flatWhatsmeowGrpc : "localhost:50051",
471
+ binaryPath: typeof flatWhatsmeowBinary === "string" ? flatWhatsmeowBinary : "",
472
+ },
473
+ };
474
+ // Drop the flat keys from the merged object so they don't leak as
475
+ // loose top-level Config keys (the `Config` interface exposes only
476
+ // the nested `drivers` block).
477
+ delete cfg.driver_primary;
478
+ delete cfg.driver_fallback_cooldown_ms;
479
+ delete cfg.driver_verify_window_ms;
480
+ delete cfg.driver_baileys_enabled;
481
+ delete cfg.driver_whatsmeow_enabled;
482
+ delete cfg.driver_whatsmeow_grpc_address;
483
+ delete cfg.driver_whatsmeow_binary_path;
282
484
  return cfg;
283
485
  }
284
486
  export const CONFIG = normalize({
@@ -302,6 +504,8 @@ export async function reloadConfig() {
302
504
  PLUGINS.push(...(CONFIG.PLUGINS || []));
303
505
  CHATS.length = 0;
304
506
  CHATS.push(...(CONFIG.CHATS || []));
507
+ EXCLUDE_CHATS.length = 0;
508
+ EXCLUDE_CHATS.push(...(CONFIG.EXCLUDE_CHATS || []));
305
509
  }
306
510
  // ---------------------------------------------------------------------------
307
511
  // Named exports — identical shape regardless of config source
@@ -309,11 +513,25 @@ export async function reloadConfig() {
309
513
  export const CLIENT_ID = CONFIG.CLIENT_ID;
310
514
  export const CMD_PREFIX = CONFIG.CMD_PREFIX;
311
515
  export const CHATS = CONFIG.CHATS;
516
+ export const EXCLUDE_CHATS = CONFIG.EXCLUDE_CHATS;
517
+ export const SECURITY_LEVEL = CONFIG.SECURITY_LEVEL;
312
518
  export const PLUGINS = CONFIG.PLUGINS;
313
519
  export const LANGUAGE = CONFIG.LANGUAGE;
314
520
  export const PHONE_NUMBER = CONFIG.PHONE_NUMBER;
315
- export const PLATFORM = CONFIG.PLATFORM;
316
521
  export const LOGIN_METHOD = CONFIG.LOGIN_METHOD;
522
+ export const ADMIN_JID = CONFIG.ADMIN_JID;
523
+ export const SMTP_HOST = CONFIG.SMTP_HOST;
524
+ export const SMTP_PORT = CONFIG.SMTP_PORT;
525
+ export const SMTP_SEC = CONFIG.SMTP_SEC;
526
+ export const SMTP_USER = CONFIG.SMTP_USER;
527
+ export const SMTP_PASS = CONFIG.SMTP_PASS;
528
+ export const SMTP_FROM = CONFIG.SMTP_FROM;
529
+ export const SMTP_TO = CONFIG.SMTP_TO;
530
+ export const SMTP_INSECURE = CONFIG.SMTP_INSECURE;
531
+ export const UPDATE_CHECK_ENABLED = CONFIG.UPDATE_CHECK_ENABLED;
532
+ export const UPDATE_CHECK_INTERVAL_HOURS = CONFIG.UPDATE_CHECK_INTERVAL_HOURS;
533
+ export const STATUS_ENABLED = CONFIG.STATUS_ENABLED;
534
+ export const STATUS_PORT = CONFIG.STATUS_PORT;
317
535
  /**
318
536
  * Writes a single value back to manybot.toml without rewriting the whole
319
537
  * file (preserves comments and the rest of the content). If the key