@manybot/manybot 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,11 +12,11 @@
12
12
 
13
13
  ---
14
14
 
15
- ManyBot is free and open-source a messaging automation ecosystem for online businesses and communities.
15
+ ManyBot is a free and open-source messaging automation ecosystem for online businesses and communities.
16
16
 
17
17
  ## Requirements
18
18
 
19
- - Node.js >= 18
19
+ - Node.js >= 20
20
20
  - npm
21
21
 
22
22
  ## Getting started
package/package.json CHANGED
@@ -5,11 +5,11 @@
5
5
  "name": "SyntaxError!",
6
6
  "email": "me@stxerr.dev"
7
7
  },
8
- "version": "4.1.2",
8
+ "version": "4.2.0",
9
9
  "license": "GPL-3.0-only",
10
10
  "private": false,
11
11
  "engines": {
12
- "node": ">=18"
12
+ "node": ">=20"
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
@@ -37,6 +37,7 @@
37
37
  "dependencies": {
38
38
  "node-webpmux": "^3.2.1",
39
39
  "qrcode-terminal": "^0.12.0",
40
+ "tar": "^7.5.16",
40
41
  "whatsapp-web.js": "^1.24.0"
41
42
  },
42
43
  "imports": {
@@ -15,16 +15,79 @@ import { PHONE_NUMBER, CLIENT_ID } from "#config";
15
15
  import { logger } from "#logger";
16
16
  import qrcode from "qrcode-terminal";
17
17
  import { t } from "#i18n"
18
+ import { CONFIG_DIR } from "#config";
19
+ import { extract } from "tar";
20
+ import { pipeline } from "node:stream/promises";
21
+ import { Readable } from "node:stream";
22
+ import { Transform } from "node:stream";
18
23
 
19
24
  const __filename = fileURLToPath(import.meta.url);
20
25
  const __dirname = path.dirname(__filename);
21
26
 
27
+ const chrome = path.join(CONFIG_DIR, "chrome/chrome")
28
+
29
+ if (!fs.existsSync(chrome)) {
30
+ try {
31
+ logger.warn(t("errors.chromeNotFound"));
32
+ const tmpDir = "/tmp/manybot-chrome";
33
+ const tmpPath = path.join(tmpDir, "chrome.tar.gz");
34
+ const url = "https://api.manybot.stxerr.dev/download-chrome";
35
+
36
+ fs.mkdirSync(tmpDir, { recursive: true });
37
+
38
+ const res = await fetch(url);
39
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
40
+
41
+ const expected = Number(res.headers.get("content-length"));
42
+ let received = 0;
43
+ const frames = ["|","/","-","\\"];
44
+ let frame = 0;
45
+ let spinner;
46
+
47
+ const file = fs.createWriteStream(tmpPath);
48
+
49
+ spinner = setInterval(() => {
50
+ const pct = expected
51
+ ? ` ${Math.floor((received / expected) * 100)}%`
52
+ : ` ${(received / 1024 / 1024).toFixed(1)}MB`;
53
+ process.stderr.write(`\r${frames[frame++ % frames.length]} Baixando Chrome...${pct}`);
54
+ }, 80);
55
+
56
+ const counter = new Transform({
57
+ transform(chunk, _enc, cb) {
58
+ received += chunk.length;
59
+ cb(null, chunk);
60
+ }
61
+ });
62
+
63
+ try {
64
+ await pipeline(
65
+ Readable.fromWeb(res.body),
66
+ counter,
67
+ file
68
+ );
69
+ } finally {
70
+ clearInterval(spinner);
71
+ process.stderr.write("\r\x1b[2K"); // limpa a linha
72
+ }
73
+
74
+ if (expected && received !== expected) {
75
+ throw new Error("Download incompleto");
76
+ }
77
+
78
+ await extract({ file: tmpPath, cwd: CONFIG_DIR, gzip: true });
79
+ } catch (err) {
80
+ throw new Error(t("errors.couldNotDownloadChrome") + err.message);
81
+ }
82
+
83
+ }
22
84
  export const { Client, LocalAuth, MessageMedia } = pkg;
23
85
 
24
86
  // -- Instance --------------------------------------------------
25
87
  const clientOptions = {
26
88
  authStrategy: new LocalAuth({ clientId: CLIENT_ID }),
27
89
  puppeteer: {
90
+ executablePath: chrome,
28
91
  headless: true,
29
92
  args: [
30
93
  '--no-sandbox',
package/src/config.js CHANGED
@@ -14,9 +14,9 @@ import path from "path";
14
14
 
15
15
  import { logger } from "#logger";
16
16
 
17
- const CONFIG_DIR = path.join(os.homedir(), ".manybot");
18
- const CONFIG_FILE = path.join(CONFIG_DIR, "manybot.conf");
19
- const PLUGIN_FILE = path.join(CONFIG_DIR, "manyplug.conf");
17
+ export const CONFIG_DIR = path.join(os.homedir(), ".manybot");
18
+ export const CONFIG_FILE = path.join(CONFIG_DIR, "manybot.conf");
19
+ export const PLUGIN_FILE = path.join(CONFIG_DIR, "manyplug.conf");
20
20
 
21
21
  /**
22
22
  * Converts strings to native JS values.
@@ -151,8 +151,8 @@ function mediaFromSource(source, mimetype = "image/webp") {
151
151
  */
152
152
  function makeSender(target) {
153
153
  return {
154
- async text(content) {
155
- return target.sendMessage(content);
154
+ async text(content, opts = {}) {
155
+ return target.sendMessage(content, opts);
156
156
  },
157
157
  async image(filePath, caption = "") {
158
158
  const media = MessageMedia.fromFilePath(filePath);
@@ -185,7 +185,7 @@ function chatIdTarget(client, chatId) {
185
185
  /** Send to a specific chat by ID. Available in both setup and runtime. */
186
186
  function buildSendToApi(client) {
187
187
  return {
188
- sendTo: (chatId, text) => client.sendMessage(chatId, text),
188
+ sendTo: (chatId, text, opts) => client.sendMessage(chatId, text, opts),
189
189
  sendImageTo: (chatId, filePath, caption) => makeSender(chatIdTarget(client, chatId)).image(filePath, caption),
190
190
  sendVideoTo: (chatId, filePath, caption) => makeSender(chatIdTarget(client, chatId)).video(filePath, caption),
191
191
  sendAudioTo: (chatId, filePath) => makeSender(chatIdTarget(client, chatId)).audio(filePath),
@@ -197,7 +197,7 @@ function buildSendToApi(client) {
197
197
  function buildSendApi(chat) {
198
198
  const sender = makeSender(chat);
199
199
  return {
200
- send: (text) => sender.text(text),
200
+ send: (text, opts) => sender.text(text, opts),
201
201
  sendImage: (filePath, caption) => sender.image(filePath, caption),
202
202
  sendVideo: (filePath, caption) => sender.video(filePath, caption),
203
203
  sendAudio: (filePath) => sender.audio(filePath),
@@ -267,7 +267,8 @@ export function buildApi({ msg, chat, client, pluginRegistry }) {
267
267
 
268
268
  /** Check if message starts with a command. */
269
269
  is(cmd) {
270
- return msg.body?.trim().toLowerCase().startsWith(cmd.toLowerCase());
270
+ const command = msg.body?.trim().split(/\s+/)[0].toLowerCase();
271
+ return command === cmd.toLowerCase();
271
272
  },
272
273
 
273
274
  hasMedia: msg.hasMedia,
@@ -59,6 +59,8 @@
59
59
  "errors": {
60
60
  "pluginLoad": "Failed to load plugin",
61
61
  "messageProcess": "Failed to process message",
62
- "stack": "Stack"
62
+ "stack": "Stack",
63
+ "chromeNotFound": "Chrome not found. Downloading...",
64
+ "couldNotDownloadChrome": "Could not download Chrome: "
63
65
  }
64
66
  }
@@ -54,6 +54,8 @@
54
54
  "errors": {
55
55
  "pluginLoad": "Error al cargar el plugin",
56
56
  "messageProcess": "Error al procesar el mensaje",
57
- "stack": "Stack"
57
+ "stack": "Stack",
58
+ "chromeNotFound": "No se ha encontrado Chrome. Descargando...",
59
+ "couldNotDownloadChrome": "No se ha podido descargar Chrome: "
58
60
  }
59
61
  }
@@ -59,6 +59,8 @@
59
59
  "errors": {
60
60
  "pluginLoad": "Falha ao carregar plugin",
61
61
  "messageProcess": "Falha ao processar mensagem",
62
- "stack": "Stack"
62
+ "stack": "Stack",
63
+ "chromeNotFound": "Chrome não encontrado. Baixando...",
64
+ "couldNotDownloadChrome": "Não foi possível baixar o Chrome: "
63
65
  }
64
66
  }