@manybot/manybot 4.3.1 → 4.4.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 +1 -1
- package/package.json +1 -1
- package/src/client/whatsappClient.js +14 -2
- package/src/kernel/messageHandler.js +2 -6
- package/src/kernel/pluginApi.js +197 -49
- package/src/kernel/pluginLoader.js +3 -1
- package/src/locales/en.json +2 -1
- package/src/locales/es.json +2 -1
- package/src/locales/pt.json +3 -1
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -24,6 +24,8 @@ import { Transform } from "node:stream";
|
|
|
24
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
25
|
const __dirname = path.dirname(__filename);
|
|
26
26
|
|
|
27
|
+
const DATA_PATH = path.join(CONFIG_DIR, "sessions");
|
|
28
|
+
|
|
27
29
|
const chrome = path.join(CONFIG_DIR, "chrome/chrome")
|
|
28
30
|
|
|
29
31
|
if (!fs.existsSync(chrome)) {
|
|
@@ -31,8 +33,15 @@ if (!fs.existsSync(chrome)) {
|
|
|
31
33
|
logger.warn(t("errors.chromeNotFound"));
|
|
32
34
|
const tmpDir = "/tmp/manybot-chrome";
|
|
33
35
|
const tmpPath = path.join(tmpDir, "chrome.tar.gz");
|
|
34
|
-
const
|
|
36
|
+
const os = process.platform;
|
|
37
|
+
const urls = {
|
|
38
|
+
linux: "https://api.manybot.stxerr.dev/download-chrome-linux",
|
|
39
|
+
win32: "https://api.manybot.stxerr.dev/download-chrome-win"
|
|
40
|
+
}
|
|
35
41
|
|
|
42
|
+
const url = urls[os];
|
|
43
|
+
if (!url) throw new Error(t("errors.OSNotSupported", { os }));
|
|
44
|
+
|
|
36
45
|
fs.mkdirSync(tmpDir, { recursive: true });
|
|
37
46
|
|
|
38
47
|
const res = await fetch(url);
|
|
@@ -85,7 +94,10 @@ export const { Client, LocalAuth, MessageMedia } = pkg;
|
|
|
85
94
|
|
|
86
95
|
// -- Instance --------------------------------------------------
|
|
87
96
|
const clientOptions = {
|
|
88
|
-
authStrategy: new LocalAuth({
|
|
97
|
+
authStrategy: new LocalAuth({
|
|
98
|
+
clientId: CLIENT_ID,
|
|
99
|
+
dataPath: DATA_PATH
|
|
100
|
+
}),
|
|
89
101
|
puppeteer: {
|
|
90
102
|
executablePath: chrome,
|
|
91
103
|
headless: true,
|
|
@@ -26,14 +26,10 @@ export async function handleMessage(msg) {
|
|
|
26
26
|
|
|
27
27
|
if (CHATS.length > 0 && !CHATS.includes(chatId)) return;
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
msg,
|
|
31
|
-
chat,
|
|
32
|
-
client,
|
|
33
|
-
pluginRegistry
|
|
34
|
-
});
|
|
29
|
+
const baseCtx = buildApi({ msg, chat, client, pluginRegistry });
|
|
35
30
|
|
|
36
31
|
for (const plugin of pluginRegistry.values()) {
|
|
32
|
+
const ctx = { ...baseCtx, storage: buildStorageApi(plugin.name) };
|
|
37
33
|
await runPlugin(plugin, ctx);
|
|
38
34
|
}
|
|
39
35
|
}
|
package/src/kernel/pluginApi.js
CHANGED
|
@@ -5,20 +5,44 @@
|
|
|
5
5
|
* Plugins can only do what's here — never touch client directly.
|
|
6
6
|
*
|
|
7
7
|
* `chat` is already filtered by kernel (only allowed chats from .conf),
|
|
8
|
-
* so plugins don't need and can't choose destination.
|
|
8
|
+
* so plugins don't need and can't choose destination, unless they use sendTo.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { logger } from "#logger";
|
|
12
12
|
import { t, createPluginT, reloadTranslations,
|
|
13
13
|
getCurrentLang } from "#i18n";
|
|
14
|
-
import { CONFIG }
|
|
14
|
+
import { CONFIG, CONFIG_DIR } from "#config";
|
|
15
15
|
import { enqueue } from "#download";
|
|
16
16
|
import { emptyFolder } from "#utils/file";
|
|
17
17
|
import { getChatId } from "#utils/getChatId";
|
|
18
18
|
import pkg from "whatsapp-web.js";
|
|
19
|
+
import { mkdirSync } from "fs";
|
|
19
20
|
|
|
20
21
|
const { MessageMedia } = pkg;
|
|
21
22
|
|
|
23
|
+
// ── Storage API ──────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export function buildStorageApi(pluginName) {
|
|
26
|
+
const dir = path.join(CONFIG_DIR, "data", pluginName);
|
|
27
|
+
mkdirSync(dir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
dir,
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resolves a path inside data directory.
|
|
34
|
+
* Make subdirectories automatically.
|
|
35
|
+
* @param {string} relativePath
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
path(relativePath) {
|
|
39
|
+
const resolved = path.join(dir, relativePath);
|
|
40
|
+
mkdirSync(path.dirname(resolved), { recursive: true });
|
|
41
|
+
return resolved;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
22
46
|
// ── Config API ───────────────────────────────────────────────────────────────
|
|
23
47
|
|
|
24
48
|
function buildConfigApi() {
|
|
@@ -136,7 +160,32 @@ const log = {
|
|
|
136
160
|
success: (...a) => logger.success(...a),
|
|
137
161
|
};
|
|
138
162
|
|
|
139
|
-
//
|
|
163
|
+
// ── Contact API ──────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Normalizes a raw whatsapp-web.js Contact into a plain object.
|
|
167
|
+
* Used internally so both ctx.contacts and ctx.msg.getContact()
|
|
168
|
+
* always return the same shape.
|
|
169
|
+
* @param {import("whatsapp-web.js").Contact} c
|
|
170
|
+
* @returns {object}
|
|
171
|
+
*/
|
|
172
|
+
function normalizeContact(c) {
|
|
173
|
+
return {
|
|
174
|
+
id: c.id._serialized,
|
|
175
|
+
number: c.number,
|
|
176
|
+
pushname: c.pushname ?? null,
|
|
177
|
+
name: c.name ?? null,
|
|
178
|
+
shortName: c.shortName ?? null,
|
|
179
|
+
isBusiness: c.isBusiness,
|
|
180
|
+
isEnterprise: c.isEnterprise,
|
|
181
|
+
isBlocked: c.isBlocked,
|
|
182
|
+
isMe: c.isMe,
|
|
183
|
+
isMyContact: c.isMyContact,
|
|
184
|
+
isWAContact: c.isWAContact,
|
|
185
|
+
isUser: c.isUser,
|
|
186
|
+
isGroup: c.isGroup,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
140
189
|
|
|
141
190
|
function buildContactsApi(client) {
|
|
142
191
|
return {
|
|
@@ -148,21 +197,7 @@ function buildContactsApi(client) {
|
|
|
148
197
|
async get(contactId) {
|
|
149
198
|
try {
|
|
150
199
|
const c = await client.getContactById(contactId);
|
|
151
|
-
return
|
|
152
|
-
id: c.id._serialized,
|
|
153
|
-
number: c.number,
|
|
154
|
-
pushname: c.pushname ?? null,
|
|
155
|
-
name: c.name ?? null,
|
|
156
|
-
shortName: c.shortName ?? null,
|
|
157
|
-
isBusiness: c.isBusiness,
|
|
158
|
-
isEnterprise: c.isEnterprise,
|
|
159
|
-
isBlocked: c.isBlocked,
|
|
160
|
-
isMe: c.isMe,
|
|
161
|
-
isMyContact: c.isMyContact,
|
|
162
|
-
isWAContact: c.isWAContact,
|
|
163
|
-
isUser: c.isUser,
|
|
164
|
-
isGroup: c.isGroup,
|
|
165
|
-
};
|
|
200
|
+
return normalizeContact(c);
|
|
166
201
|
} catch {
|
|
167
202
|
return null;
|
|
168
203
|
}
|
|
@@ -170,7 +205,7 @@ function buildContactsApi(client) {
|
|
|
170
205
|
|
|
171
206
|
/**
|
|
172
207
|
* Get the profile picture URL of a contact.
|
|
173
|
-
*
|
|
208
|
+
* Respects privacy settings — may return null.
|
|
174
209
|
* @param {string} contactId
|
|
175
210
|
* @returns {Promise<string|null>}
|
|
176
211
|
*/
|
|
@@ -202,7 +237,11 @@ function buildContactsApi(client) {
|
|
|
202
237
|
|
|
203
238
|
// ── Internal media helpers ───────────────────────────────────────────────────
|
|
204
239
|
|
|
205
|
-
|
|
240
|
+
/**
|
|
241
|
+
* @param {string|Buffer} source
|
|
242
|
+
* @param {string} mimetype — required, no ambiguous default
|
|
243
|
+
*/
|
|
244
|
+
function mediaFromSource(source, mimetype) {
|
|
206
245
|
return typeof source === "string"
|
|
207
246
|
? MessageMedia.fromFilePath(source)
|
|
208
247
|
: new MessageMedia(mimetype, source.toString("base64"));
|
|
@@ -210,7 +249,6 @@ function mediaFromSource(source, mimetype = "image/webp") {
|
|
|
210
249
|
|
|
211
250
|
/**
|
|
212
251
|
* Returns send methods bound to a target that exposes `.sendMessage()`.
|
|
213
|
-
* Used for both current-chat and sendTo variants.
|
|
214
252
|
* @param {{ sendMessage: Function }} target
|
|
215
253
|
*/
|
|
216
254
|
function makeSender(target) {
|
|
@@ -231,7 +269,7 @@ function makeSender(target) {
|
|
|
231
269
|
return target.sendMessage(media, { sendAudioAsVoice: asVoice });
|
|
232
270
|
},
|
|
233
271
|
async sticker(source) {
|
|
234
|
-
const media = mediaFromSource(source);
|
|
272
|
+
const media = mediaFromSource(source, "image/webp");
|
|
235
273
|
return target.sendMessage(media, { sendMediaAsSticker: true });
|
|
236
274
|
},
|
|
237
275
|
};
|
|
@@ -244,34 +282,93 @@ function chatIdTarget(client, chatId) {
|
|
|
244
282
|
};
|
|
245
283
|
}
|
|
246
284
|
|
|
247
|
-
// ── Send
|
|
285
|
+
// ── Send API ─────────────────────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Runtime send API — current chat + .to() for other chats.
|
|
289
|
+
*
|
|
290
|
+
* ctx.send.text("oi")
|
|
291
|
+
* ctx.send.image("./foto.jpg", "legenda")
|
|
292
|
+
* ctx.send.to("5511@c.us").text("oi")
|
|
293
|
+
*/
|
|
294
|
+
function buildSendApi(chat, client) {
|
|
295
|
+
const current = makeSender(chat);
|
|
248
296
|
|
|
249
|
-
/** Send to a specific chat by ID. Available in both setup and runtime. */
|
|
250
|
-
function buildSendToApi(client) {
|
|
251
297
|
return {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
298
|
+
send: {
|
|
299
|
+
text: (text, opts) => current.text(text, opts),
|
|
300
|
+
image: (filePath, caption) => current.image(filePath, caption),
|
|
301
|
+
video: (filePath, caption) => current.video(filePath, caption),
|
|
302
|
+
audio: (filePath, opts) => current.audio(filePath, opts),
|
|
303
|
+
sticker: (source) => current.sticker(source),
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Returns a sender bound to another chat.
|
|
307
|
+
* @param {string} chatId
|
|
308
|
+
* @returns {{ text, image, video, audio, sticker }}
|
|
309
|
+
*/
|
|
310
|
+
to: (chatId) => makeSender(chatIdTarget(client, chatId)),
|
|
311
|
+
},
|
|
257
312
|
};
|
|
258
313
|
}
|
|
259
314
|
|
|
260
|
-
/**
|
|
261
|
-
|
|
262
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Setup send API — no current chat, only .to().
|
|
317
|
+
*
|
|
318
|
+
* ctx.send.to(adminChatId).text("bot iniciado")
|
|
319
|
+
*/
|
|
320
|
+
function buildSetupSendApi(client) {
|
|
263
321
|
return {
|
|
264
|
-
send:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
322
|
+
send: {
|
|
323
|
+
to: (chatId) => makeSender(chatIdTarget(client, chatId)),
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ── Events API (setup only) ───────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
function buildEventsApi(client) {
|
|
331
|
+
return {
|
|
332
|
+
/**
|
|
333
|
+
* Registers a persistent listener for a client event.
|
|
334
|
+
* Returns an 'off()' function to cancel the listener when the plugin wants.
|
|
335
|
+
*
|
|
336
|
+
* @param {string} event
|
|
337
|
+
* @param {Function} handler
|
|
338
|
+
* @returns {Function} off
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* const off = ctx.events.on("group_join", (notification) => { ... });
|
|
342
|
+
* // cancels when the plugin doesn't want anymore:
|
|
343
|
+
* off();
|
|
344
|
+
*/
|
|
345
|
+
on(event, handler) {
|
|
346
|
+
client.on(event, handler);
|
|
347
|
+
return () => client.off(event, handler);
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Returns a Promise that resolves on the next ocurrence of the event.
|
|
352
|
+
* Useful for waiting a specific event without having to manage listeners manually.
|
|
353
|
+
*
|
|
354
|
+
* @param {string} event
|
|
355
|
+
* @returns {Promise<any>}
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* const notification = await ctx.events.once("group_join");
|
|
359
|
+
*/
|
|
360
|
+
once(event) {
|
|
361
|
+
return new Promise((resolve) => client.once(event, resolve));
|
|
362
|
+
}
|
|
269
363
|
};
|
|
270
364
|
}
|
|
271
365
|
|
|
272
366
|
// ── Base API (shared between setup and runtime) ───────────────────────────────
|
|
273
367
|
|
|
274
|
-
function buildBaseApi(client, pluginRegistry) {
|
|
368
|
+
function buildBaseApi(client, pluginRegistry, pluginName) {
|
|
369
|
+
const botId = client.info?.wid?._serialized ?? null;
|
|
370
|
+
if (!botId) logger.warn("[pluginApi] botId is null - client may not be ready yet.");
|
|
371
|
+
|
|
275
372
|
return {
|
|
276
373
|
log,
|
|
277
374
|
t,
|
|
@@ -280,9 +377,9 @@ function buildBaseApi(client, pluginRegistry) {
|
|
|
280
377
|
utils: buildUtilsApi(),
|
|
281
378
|
download: buildDownloadApi(),
|
|
282
379
|
plugins: buildPluginsApi(pluginRegistry),
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
380
|
+
contacts: buildContactsApi(client),
|
|
381
|
+
storage: buildStorageApi(pluginName),
|
|
382
|
+
botId,
|
|
286
383
|
};
|
|
287
384
|
}
|
|
288
385
|
|
|
@@ -296,9 +393,11 @@ function buildBaseApi(client, pluginRegistry) {
|
|
|
296
393
|
* @param {Map<string, any>} pluginRegistry
|
|
297
394
|
* @returns {object}
|
|
298
395
|
*/
|
|
299
|
-
export function buildSetupApi(client, pluginRegistry) {
|
|
396
|
+
export function buildSetupApi(client, pluginRegistry, pluginName) {
|
|
300
397
|
return {
|
|
301
|
-
...buildBaseApi(client, pluginRegistry),
|
|
398
|
+
...buildBaseApi(client, pluginRegistry, pluginName),
|
|
399
|
+
...buildSetupSendApi(client),
|
|
400
|
+
events: buildEventsApi(client),
|
|
302
401
|
};
|
|
303
402
|
}
|
|
304
403
|
|
|
@@ -316,9 +415,15 @@ export function buildSetupApi(client, pluginRegistry) {
|
|
|
316
415
|
* @returns {object} ctx
|
|
317
416
|
*/
|
|
318
417
|
export function buildApi({ msg, chat, client, pluginRegistry }) {
|
|
418
|
+
const prefix = CONFIG.CMD_PREFIX ?? "!";
|
|
419
|
+
const rawArgs = msg.body?.trim().split(/\s+/) ?? [];
|
|
420
|
+
const command = rawArgs[0]?.toLowerCase().startsWith(prefix)
|
|
421
|
+
? rawArgs[0].slice(prefix.length).toLowerCase()
|
|
422
|
+
: rawArgs[0]?.toLowerCase() ?? "";
|
|
423
|
+
|
|
319
424
|
return {
|
|
320
425
|
...buildBaseApi(client, pluginRegistry),
|
|
321
|
-
...buildSendApi(chat),
|
|
426
|
+
...buildSendApi(chat, client),
|
|
322
427
|
|
|
323
428
|
// ── msg ──────────────────────────────────────────────────
|
|
324
429
|
|
|
@@ -328,11 +433,18 @@ export function buildApi({ msg, chat, client, pluginRegistry }) {
|
|
|
328
433
|
fromMe: msg.fromMe,
|
|
329
434
|
sender: msg.author || msg.from,
|
|
330
435
|
senderName: msg._data?.notifyName || String(msg.from).replace(/(:\d+)?@.*$/, ""),
|
|
331
|
-
args: msg.body?.trim().split(/\s+/) ?? [],
|
|
332
436
|
|
|
333
|
-
/**
|
|
437
|
+
/** Command token without prefix (e.g. "play" for "!play foo"). */
|
|
438
|
+
command,
|
|
439
|
+
|
|
440
|
+
/** Arguments after the command token. */
|
|
441
|
+
args: rawArgs.slice(1),
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Check if message is a given command.
|
|
445
|
+
* @param {string} cmd — without prefix
|
|
446
|
+
*/
|
|
334
447
|
is(cmd) {
|
|
335
|
-
const command = msg.body?.trim().split(/\s+/)[0].toLowerCase();
|
|
336
448
|
return command === cmd.toLowerCase();
|
|
337
449
|
},
|
|
338
450
|
|
|
@@ -360,8 +472,18 @@ export function buildApi({ msg, chat, client, pluginRegistry }) {
|
|
|
360
472
|
return msg.react(emoji);
|
|
361
473
|
},
|
|
362
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Get the sender as a normalized Contact object.
|
|
477
|
+
* Same shape as ctx.contacts.get().
|
|
478
|
+
* @returns {Promise<object|null>}
|
|
479
|
+
*/
|
|
363
480
|
async getContact() {
|
|
364
|
-
|
|
481
|
+
try {
|
|
482
|
+
const c = await msg.getContact();
|
|
483
|
+
return normalizeContact(c);
|
|
484
|
+
} catch {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
365
487
|
},
|
|
366
488
|
},
|
|
367
489
|
|
|
@@ -371,6 +493,32 @@ export function buildApi({ msg, chat, client, pluginRegistry }) {
|
|
|
371
493
|
id: chat.id._serialized,
|
|
372
494
|
name: chat.name || chat.id.user,
|
|
373
495
|
isGroup: /@g\.us$/.test(chat.id._serialized),
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* List of group participants.
|
|
499
|
+
* Returns [] for non-group chats.
|
|
500
|
+
* @returns {Promise<Array<{ id: string, isAdmin: boolean, isSuperAdmin: boolean }>>}
|
|
501
|
+
*/
|
|
502
|
+
async getParticipants() {
|
|
503
|
+
if (!chat.participants) return [];
|
|
504
|
+
return chat.participants.map((p) => ({
|
|
505
|
+
id: p.id._serialized,
|
|
506
|
+
isAdmin: p.isAdmin,
|
|
507
|
+
isSuperAdmin: p.isSuperAdmin,
|
|
508
|
+
}));
|
|
509
|
+
},
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Check if a contact is an admin of this group.
|
|
513
|
+
* Always returns false for non-group chats.
|
|
514
|
+
* @param {string} contactId
|
|
515
|
+
* @returns {Promise<boolean>}
|
|
516
|
+
*/
|
|
517
|
+
async isAdmin(contactId) {
|
|
518
|
+
return chat.participants?.some(
|
|
519
|
+
(p) => p.id._serialized === contactId && (p.isAdmin || p.isSuperAdmin)
|
|
520
|
+
) ?? false;
|
|
521
|
+
},
|
|
374
522
|
},
|
|
375
523
|
};
|
|
376
524
|
}
|
|
@@ -15,6 +15,7 @@ import { logger } from "#logger";
|
|
|
15
15
|
import { t } from "#i18n";
|
|
16
16
|
import { pathToFileURL } from "url";
|
|
17
17
|
import { PATHS } from "#config";
|
|
18
|
+
import { buildStorageApi } from "#manyapi";
|
|
18
19
|
|
|
19
20
|
const PLUGINS_DIR = path.join(PATHS.HOME, "plugins");
|
|
20
21
|
|
|
@@ -63,10 +64,11 @@ export async function loadPlugins(activePlugins) {
|
|
|
63
64
|
*
|
|
64
65
|
* @param {object} api — api without message context (only sendTo, log, schedule...)
|
|
65
66
|
*/
|
|
66
|
-
export async function setupPlugins(
|
|
67
|
+
export async function setupPlugins(baseApi) {
|
|
67
68
|
for (const plugin of pluginRegistry.values()) {
|
|
68
69
|
if (plugin.status !== "active" || !plugin.setup) continue;
|
|
69
70
|
try {
|
|
71
|
+
const api = { ...baseApi, storage: buildStorageApi(plugin.name) };
|
|
70
72
|
await plugin.setup(api);
|
|
71
73
|
} catch (err) {
|
|
72
74
|
logger.error(t("system.pluginSetupFailed", { name: plugin.name, message: err.message }));
|
package/src/locales/en.json
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"messageProcess": "Failed to process message",
|
|
62
62
|
"stack": "Stack",
|
|
63
63
|
"chromeNotFound": "Chrome not found. Downloading...",
|
|
64
|
-
"couldNotDownloadChrome": "Could not download Chrome: "
|
|
64
|
+
"couldNotDownloadChrome": "Could not download Chrome: ",
|
|
65
|
+
"OSNotSupported": "Unsupported operating system: {{os}}. If you have any questions, please visit: https://manybot.stxerr.dev/docs/getting-started/"
|
|
65
66
|
}
|
|
66
67
|
}
|
package/src/locales/es.json
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"messageProcess": "Error al procesar el mensaje",
|
|
57
57
|
"stack": "Stack",
|
|
58
58
|
"chromeNotFound": "No se ha encontrado Chrome. Descargando...",
|
|
59
|
-
"couldNotDownloadChrome": "No se ha podido descargar Chrome: "
|
|
59
|
+
"couldNotDownloadChrome": "No se ha podido descargar Chrome: ",
|
|
60
|
+
"OSNotSupported": "Sistema operativo no compatible: {{os}}. Si tienes alguna duda, consulta: https://manybot.stxerr.dev/docs/getting-started/"
|
|
60
61
|
}
|
|
61
62
|
}
|
package/src/locales/pt.json
CHANGED
|
@@ -61,6 +61,8 @@
|
|
|
61
61
|
"messageProcess": "Falha ao processar mensagem",
|
|
62
62
|
"stack": "Stack",
|
|
63
63
|
"chromeNotFound": "Chrome não encontrado. Baixando...",
|
|
64
|
-
"couldNotDownloadChrome": "Não foi possível baixar o Chrome: "
|
|
64
|
+
"couldNotDownloadChrome": "Não foi possível baixar o Chrome: ",
|
|
65
|
+
"OSNotSupported": "Sistema operacional não suportado: {{os}}. Em caso de dúvidas, consulte: https://manybot.stxerr.dev/docs/getting-started/"
|
|
66
|
+
|
|
65
67
|
}
|
|
66
68
|
}
|