From e7a8e85ead9a7dffbdbb04e172f83c3f66bc7262 Mon Sep 17 00:00:00 2001
From: lisandroprada
Date: Wed, 25 Jan 2023 08:21:12 -0300
Subject: [PATCH 06/21] Update index.mdx
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Agregado: Definición de la constante BOTNAME.
---
packages/docs/src/routes/docs/flows/index.mdx | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx
index 0cb1222..cf6c23c 100644
--- a/packages/docs/src/routes/docs/flows/index.mdx
+++ b/packages/docs/src/routes/docs/flows/index.mdx
@@ -226,6 +226,7 @@ async (ctx,{flowDynamic, endFlow})=>{
Argumento para asignar nombre y puerto al BOT
```js
+const BOTNAME = 'bot';
QRPortalWeb({name:BOTNAME, port:3005 });
```
From 9dd7c02b6a5474aff063f7d6be0ca8519504b93c Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Wed, 25 Jan 2023 16:10:13 -0500
Subject: [PATCH 07/21] feat(provider): :rocket: implements all send media to
venom provider
---
packages/provider/src/venom/index.js | 67 +++++++++++++++++++++++++---
1 file changed, 62 insertions(+), 5 deletions(-)
diff --git a/packages/provider/src/venom/index.js b/packages/provider/src/venom/index.js
index 4b7c231..10fe5aa 100644
--- a/packages/provider/src/venom/index.js
+++ b/packages/provider/src/venom/index.js
@@ -2,18 +2,20 @@ const { ProviderClass } = require('@bot-whatsapp/bot')
const venom = require('venom-bot')
const { createWriteStream } = require('fs')
const { Console } = require('console')
+const mime = require('mime-types')
const {
venomCleanNumber,
venomGenerateImage,
venomisValidNumber,
- venomDownloadMedia,
} = require('./utils')
const logger = new Console({
stdout: createWriteStream(`${process.cwd()}/venom.log`),
})
+const { generalDownload } = require('../../common/download')
+
/**
* ⚙️ VenomProvider: Es una clase tipo adaptor
* que extiende clases de ProviderClass (la cual es como interfaz para sber que funciones rqueridas)
@@ -134,6 +136,53 @@ class VenomProvider extends ProviderClass {
// return this.vendor.sendButtons(number, "Title", buttons1, "Description");
}
+ /**
+ * Enviar audio
+ * @alpha
+ * @param {string} number
+ * @param {string} message
+ * @param {boolean} voiceNote optional
+ * @example await sendMessage('+XXXXXXXXXXX', 'audio.mp3')
+ */
+
+ sendAudio = async (number, audioPath, voiceNote = false) => {
+ return this.vendor.sendVoice(number, audioPath)
+ }
+
+ /**
+ * Enviar imagen
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendImage = async (number, filePath, text) => {
+ return this.vendor.sendImage(number, filePath, 'image-name', text)
+ }
+
+ /**
+ *
+ * @param {string} number
+ * @param {string} filePath
+ * @example await sendMessage('+XXXXXXXXXXX', './document/file.pdf')
+ */
+
+ sendFile = async (number, filePath, text) => {
+ const fileName = filePath.split('/').pop()
+ return this.vendor.sendFile(number, filePath, fileName, text)
+ }
+
+ /**
+ * Enviar video
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendVideo = async (number, filePath, text) => {
+ return this.vendor.sendVideoAsGif(number, filePath, 'video.gif', text)
+ }
+
/**
* Enviar imagen o multimedia
* @param {*} number
@@ -141,10 +190,18 @@ class VenomProvider extends ProviderClass {
* @param {*} message
* @returns
*/
- sendMedia = async (number, mediaInput, message) => {
- if (!mediaInput) throw new Error(`NO_SE_ENCONTRO: ${mediaInput}`)
- const fileDownloaded = await venomDownloadMedia(mediaInput)
- return this.vendor.sendImage(number, fileDownloaded, '.', message)
+ sendMedia = async (number, mediaUrl, text) => {
+ const fileDownloaded = await generalDownload(mediaUrl)
+ const mimeType = mime.lookup(fileDownloaded)
+
+ if (mimeType.includes('image'))
+ return this.sendImage(number, fileDownloaded, text)
+ if (mimeType.includes('video'))
+ return this.sendVideo(number, fileDownloaded, text)
+ if (mimeType.includes('audio'))
+ return this.sendAudio(number, fileDownloaded)
+
+ return this.sendFile(number, fileDownloaded, text)
}
/**
From 6ff1a3a980196c01c66ed04ee07d0e7e57256504 Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 12:51:15 -0500
Subject: [PATCH 08/21] feat(provider): :rocket: send file wwebjs
---
packages/provider/src/web-whatsapp/index.js | 122 +++++++++++++++++---
1 file changed, 104 insertions(+), 18 deletions(-)
diff --git a/packages/provider/src/web-whatsapp/index.js b/packages/provider/src/web-whatsapp/index.js
index f7f8bd0..2709960 100644
--- a/packages/provider/src/web-whatsapp/index.js
+++ b/packages/provider/src/web-whatsapp/index.js
@@ -1,7 +1,7 @@
const { Client, LocalAuth, MessageMedia, Buttons } = require('whatsapp-web.js')
const { ProviderClass } = require('@bot-whatsapp/bot')
const { Console } = require('console')
-const { createWriteStream } = require('fs')
+const { createWriteStream, readFileSync } = require('fs')
const {
wwebCleanNumber,
wwebDownloadMedia,
@@ -13,6 +13,9 @@ const logger = new Console({
stdout: createWriteStream('./log'),
})
+const { generalDownload } = require('../../common/download')
+const mime = require('mime-types')
+
/**
* ⚙️ WebWhatsappProvider: Es una clase tipo adaptor
* que extiende clases de ProviderClass (la cual es como interfaz para sber que funciones rqueridas)
@@ -35,6 +38,7 @@ class WebWhatsappProvider extends ProviderClass {
'--disable-setuid-sandbox',
'--unhandled-rejections=strict',
],
+ //executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
},
})
@@ -103,23 +107,6 @@ class WebWhatsappProvider extends ProviderClass {
},
]
- /**
- * Enviar un archivo multimedia
- * https://docs.wwebjs.dev/MessageMedia.html
- * @private
- * @param {*} number
- * @param {*} mediaInput
- * @returns
- */
- sendMedia = async (number, mediaInput = null) => {
- if (!mediaInput) throw new Error(`NO_SE_ENCONTRO: ${mediaInput}`)
- const fileDownloaded = await wwebDownloadMedia(mediaInput)
- const media = MessageMedia.fromFilePath(fileDownloaded)
- return this.vendor.sendMessage(number, media, {
- sendAudioAsVoice: true,
- })
- }
-
/**
* Enviar botones
* https://docs.wwebjs.dev/Buttons.html
@@ -170,6 +157,105 @@ class WebWhatsappProvider extends ProviderClass {
return this.vendor.sendMessage(number, message)
}
+ /**
+ * Enviar imagen
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendImage = async (number, filePath, text) => {
+ const base64 = readFileSync(filePath, { encoding: 'base64' })
+ const mimeType = mime.lookup(filePath)
+ const media = new MessageMedia(mimeType, base64)
+ return this.vendor.sendMessage(number, media, text)
+ }
+
+ /**
+ * Enviar audio
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ /**
+ * Enviar audio
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendAudio = async (number, filePath, text) => {
+ const base64 = readFileSync(filePath, { encoding: 'base64' })
+ const mimeType = mime.lookup(filePath)
+ const media = new MessageMedia(mimeType, base64)
+ return this.vendor.sendMessage(number, media, text)
+ }
+ /**
+ * Enviar audio
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendAudio = async (number, filePath, text) => {
+ const base64 = readFileSync(filePath, { encoding: 'base64' })
+ const mimeType = mime.lookup(filePath)
+ const media = new MessageMedia(mimeType, base64)
+ return this.vendor.sendMessage(number, media, text)
+ }
+
+ /**
+ * Enviar video
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendVideo = async (number, filePath) => {
+ const base64 = readFileSync(filePath, { encoding: 'base64' })
+ const mimeType = mime.lookup(filePath)
+ const media = new MessageMedia(mimeType, base64)
+ return this.vendor.sendMessage(number, media, {
+ sendMediaAsDocument: true,
+ })
+ }
+
+ /**
+ * Enviar Arhivos/pdf
+ * @param {*} number
+ * @param {*} imageUrl
+ * @param {*} text
+ * @returns
+ */
+ sendFile = async (number, filePath, text) => {
+ const base64 = readFileSync(filePath, { encoding: 'base64' })
+ const mimeType = mime.lookup(filePath)
+ const media = new MessageMedia(mimeType, base64)
+ return this.vendor.sendMessage(number, media, text)
+ }
+
+ /**
+ * Enviar imagen o multimedia
+ * @param {*} number
+ * @param {*} mediaInput
+ * @param {*} message
+ * @returns
+ */
+ sendMedia = async (number, mediaUrl, text) => {
+ const fileDownloaded = await generalDownload(mediaUrl)
+ const mimeType = mime.lookup(fileDownloaded)
+
+ if (mimeType.includes('image'))
+ return this.sendImage(number, fileDownloaded, text)
+ if (mimeType.includes('video'))
+ return this.sendVideo(number, fileDownloaded)
+ if (mimeType.includes('audio'))
+ return this.sendAudio(number, fileDownloaded)
+
+ return this.sendFile(number, fileDownloaded)
+ }
+
/**
*
* @param {*} userId
From cbe438b77854e8df48b9dafaf7a837d21124ac5f Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 14:28:25 -0500
Subject: [PATCH 09/21] feat(provider): :rocket: fix issues in providers venom
and wwebjs
---
packages/provider/src/venom/index.js | 2 +-
packages/provider/src/web-whatsapp/index.js | 34 ++++++---------------
2 files changed, 10 insertions(+), 26 deletions(-)
diff --git a/packages/provider/src/venom/index.js b/packages/provider/src/venom/index.js
index 10fe5aa..3e1b630 100644
--- a/packages/provider/src/venom/index.js
+++ b/packages/provider/src/venom/index.js
@@ -145,7 +145,7 @@ class VenomProvider extends ProviderClass {
* @example await sendMessage('+XXXXXXXXXXX', 'audio.mp3')
*/
- sendAudio = async (number, audioPath, voiceNote = false) => {
+ sendAudio = async (number, audioPath) => {
return this.vendor.sendVoice(number, audioPath)
}
diff --git a/packages/provider/src/web-whatsapp/index.js b/packages/provider/src/web-whatsapp/index.js
index 2709960..f66e97a 100644
--- a/packages/provider/src/web-whatsapp/index.js
+++ b/packages/provider/src/web-whatsapp/index.js
@@ -4,7 +4,6 @@ const { Console } = require('console')
const { createWriteStream, readFileSync } = require('fs')
const {
wwebCleanNumber,
- wwebDownloadMedia,
wwebGenerateImage,
wwebIsValidNumber,
} = require('./utils')
@@ -168,7 +167,9 @@ class WebWhatsappProvider extends ProviderClass {
const base64 = readFileSync(filePath, { encoding: 'base64' })
const mimeType = mime.lookup(filePath)
const media = new MessageMedia(mimeType, base64)
- return this.vendor.sendMessage(number, media, text)
+ return this.vendor.sendMessage(number, media, {
+ caption: 'soy una imagen',
+ })
}
/**
@@ -178,31 +179,14 @@ class WebWhatsappProvider extends ProviderClass {
* @param {*} text
* @returns
*/
- /**
- * Enviar audio
- * @param {*} number
- * @param {*} imageUrl
- * @param {*} text
- * @returns
- */
+
sendAudio = async (number, filePath, text) => {
const base64 = readFileSync(filePath, { encoding: 'base64' })
const mimeType = mime.lookup(filePath)
const media = new MessageMedia(mimeType, base64)
- return this.vendor.sendMessage(number, media, text)
- }
- /**
- * Enviar audio
- * @param {*} number
- * @param {*} imageUrl
- * @param {*} text
- * @returns
- */
- sendAudio = async (number, filePath, text) => {
- const base64 = readFileSync(filePath, { encoding: 'base64' })
- const mimeType = mime.lookup(filePath)
- const media = new MessageMedia(mimeType, base64)
- return this.vendor.sendMessage(number, media, text)
+ return this.vendor.sendMessage(number, media, {
+ caption: 'soy un audio',
+ })
}
/**
@@ -228,11 +212,11 @@ class WebWhatsappProvider extends ProviderClass {
* @param {*} text
* @returns
*/
- sendFile = async (number, filePath, text) => {
+ sendFile = async (number, filePath) => {
const base64 = readFileSync(filePath, { encoding: 'base64' })
const mimeType = mime.lookup(filePath)
const media = new MessageMedia(mimeType, base64)
- return this.vendor.sendMessage(number, media, text)
+ return this.vendor.sendMessage(number, media)
}
/**
From dcb0566d2bc3da40cd0c71554bb5ea0ec115d9ca Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 14:31:05 -0500
Subject: [PATCH 10/21] feat(provider): :rocket: fix provider venom and wwebjs
From b2afa45352a7ab1f5d9775f3c1fde475bd8ca204 Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 14:32:42 -0500
Subject: [PATCH 11/21] feat(provider): :rocket: fix provider
From f8c7184487065443ab10f77aaf585e8bd63ca441 Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 14:42:45 -0500
Subject: [PATCH 12/21] feat(provider): :rocket: fix provider
From 0ad4c58457b548dc41c0f9e8470d59c48de7b95a Mon Sep 17 00:00:00 2001
From: aurik3 <37228512+aurik3@users.noreply.github.com>
Date: Fri, 27 Jan 2023 14:51:20 -0500
Subject: [PATCH 13/21] feat(provider): :rocket: fix provider
---
packages/provider/src/web-whatsapp/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/provider/src/web-whatsapp/index.js b/packages/provider/src/web-whatsapp/index.js
index f66e97a..693d1b9 100644
--- a/packages/provider/src/web-whatsapp/index.js
+++ b/packages/provider/src/web-whatsapp/index.js
@@ -163,7 +163,7 @@ class WebWhatsappProvider extends ProviderClass {
* @param {*} text
* @returns
*/
- sendImage = async (number, filePath, text) => {
+ sendImage = async (number, filePath) => {
const base64 = readFileSync(filePath, { encoding: 'base64' })
const mimeType = mime.lookup(filePath)
const media = new MessageMedia(mimeType, base64)
@@ -180,7 +180,7 @@ class WebWhatsappProvider extends ProviderClass {
* @returns
*/
- sendAudio = async (number, filePath, text) => {
+ sendAudio = async (number, filePath) => {
const base64 = readFileSync(filePath, { encoding: 'base64' })
const mimeType = mime.lookup(filePath)
const media = new MessageMedia(mimeType, base64)
From e22780d3faba94f71a70f1f201a20690608fa5bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leifer=20Jes=C3=BAs=20Mendez?=
Date: Sat, 28 Jan 2023 15:46:13 +0100
Subject: [PATCH 14/21] fix(bot): :zap: fix fallback refactor
---
__test__/05-case.test.js | 118 ++++++++++++++++++
packages/bot/core/core.class.js | 48 ++++---
packages/docs/src/routes/docs/flows/index.mdx | 98 ++++++++-------
3 files changed, 204 insertions(+), 60 deletions(-)
create mode 100644 __test__/05-case.test.js
diff --git a/__test__/05-case.test.js b/__test__/05-case.test.js
new file mode 100644
index 0000000..6ca65d0
--- /dev/null
+++ b/__test__/05-case.test.js
@@ -0,0 +1,118 @@
+const { test } = require('uvu')
+const assert = require('uvu/assert')
+const MOCK_DB = require('../packages/database/src/mock')
+const PROVIDER_DB = require('../packages/provider/src/mock')
+const {
+ addKeyword,
+ createBot,
+ createFlow,
+ createProvider,
+} = require('../packages/bot/index')
+
+/**
+ * Falsear peticion async
+ * @param {*} fakeData
+ * @returns
+ */
+const fakeHTTP = async (fakeData = []) => {
+ await delay(5)
+ const data = fakeData.map((u, i) => ({ body: `${i + 1} ${u}` }))
+ return Promise.resolve(data)
+}
+
+test(`[Caso - 05] Continuar Flujo (continueFlow)`, async () => {
+ const MOCK_VALUES = [
+ '¿CUal es tu email?',
+ 'Continuamos....',
+ '¿Cual es tu edad?',
+ ]
+ const provider = createProvider(PROVIDER_DB)
+ const database = new MOCK_DB()
+
+ const flujoPrincipal = addKeyword(['hola'])
+ .addAnswer(
+ MOCK_VALUES[0],
+ {
+ capture: true,
+ },
+ async (ctx, { flowDynamic, fallBack }) => {
+ const validation = ctx.body.includes('@')
+
+ if (validation) {
+ const getDataFromApi = await fakeHTTP([
+ 'Gracias por tu email se ha validado de manera correcta',
+ ])
+ return flowDynamic(getDataFromApi)
+ }
+ return fallBack(validation)
+ }
+ )
+ .addAnswer(MOCK_VALUES[1])
+ .addAnswer(
+ MOCK_VALUES[2],
+ { capture: true },
+ async (ctx, { flowDynamic, fallBack }) => {
+ if (ctx.body !== '18') {
+ await delay(50)
+ return fallBack(false, 'Ups creo que no eres mayor de edad')
+ }
+ return flowDynamic('Bien tu edad es correcta!')
+ }
+ )
+ .addAnswer('Puedes pasar')
+
+ createBot({
+ database,
+ flow: createFlow([flujoPrincipal]),
+ provider,
+ })
+
+ provider.delaySendMessage(0, 'message', {
+ from: '000',
+ body: 'hola',
+ })
+
+ provider.delaySendMessage(10, 'message', {
+ from: '000',
+ body: 'this is not email value',
+ })
+
+ provider.delaySendMessage(20, 'message', {
+ from: '000',
+ body: 'test@test.com',
+ })
+
+ provider.delaySendMessage(90, 'message', {
+ from: '000',
+ body: '20',
+ })
+
+ provider.delaySendMessage(200, 'message', {
+ from: '000',
+ body: '18',
+ })
+
+ await delay(1200)
+ const getHistory = database.listHistory.map((i) => i.answer)
+ assert.is(MOCK_VALUES[0], getHistory[0])
+ assert.is('this is not email value', getHistory[1])
+ assert.is(MOCK_VALUES[0], getHistory[2])
+ assert.is('test@test.com', getHistory[3])
+ assert.is(
+ '1 Gracias por tu email se ha validado de manera correcta',
+ getHistory[4]
+ )
+ assert.is(MOCK_VALUES[1], getHistory[5])
+ assert.is(MOCK_VALUES[2], getHistory[6])
+ assert.is('20', getHistory[7])
+ assert.is('Ups creo que no eres mayor de edad', getHistory[8])
+ assert.is('18', getHistory[9])
+ assert.is('Bien tu edad es correcta!', getHistory[10])
+ assert.is('Puedes pasar', getHistory[11])
+})
+
+test.run()
+
+function delay(ms) {
+ return new Promise((res) => setTimeout(res, ms))
+}
diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js
index f7051b3..418fef4 100644
--- a/packages/bot/core/core.class.js
+++ b/packages/bot/core/core.class.js
@@ -71,8 +71,8 @@ class CoreClass {
logger.log(`[handleMsg]: `, messageCtxInComming)
const { body, from } = messageCtxInComming
let msgToSend = []
- let fallBackFlag = false
let endFlowFlag = false
+ let fallBackFlag = false
if (this.generalArgs.blackList.includes(from)) return
if (!body) return
if (!body.length) return
@@ -105,11 +105,23 @@ class CoreClass {
return
}
- // 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
- const sendFlow = async (messageToSend, numberOrId) => {
- // [1 Paso] esto esta bien!
+ // 📄 Continuar con el siguiente flujo
+ const continueFlow = async () => {
+ const cotinueMessage =
+ this.flowClass.find(refToContinue?.ref, true) || []
+ sendFlow(cotinueMessage, from, { continue: true })
+ return
+ }
+
+ // 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
+ const sendFlow = async (
+ messageToSend,
+ numberOrId,
+ options = { continue: false }
+ ) => {
+ if (!options.continue && prevMsg?.options?.capture)
+ await cbEveryCtx(prevMsg?.ref)
- if (prevMsg?.options?.capture) await cbEveryCtx(prevMsg?.ref)
const queue = []
for (const ctxMessage of messageToSend) {
if (endFlowFlag) return
@@ -127,11 +139,13 @@ class CoreClass {
}
// 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje
- const fallBack = async () => {
- fallBackFlag = true
- await this.sendProviderAndSave(from, refToContinue)
+ const fallBack = async (next = false, message = null) => {
QueuePrincipal.queue = []
- return refToContinue
+ if (next) return continueFlow()
+ return this.sendProviderAndSave(from, {
+ ...refToContinue,
+ answer: message ?? refToContinue.answer,
+ })
}
// 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes
@@ -141,8 +155,7 @@ class CoreClass {
listMsg = [],
optListMsg = { limit: 5, fallback: false }
) => {
- if (!Array.isArray(listMsg))
- throw new Error('Esto debe ser un ARRAY')
+ if (!Array.isArray(listMsg)) listMsg = [listMsg]
fallBackFlag = optListMsg.fallback
const parseListMsg = listMsg
@@ -165,7 +178,7 @@ class CoreClass {
for (const msg of parseListMsg) {
await this.sendProviderAndSave(from, msg)
}
- return
+ return continueFlow()
}
// 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback
@@ -181,11 +194,12 @@ class CoreClass {
fallBack,
flowDynamic,
endFlow,
+ continueFlow,
})
}
// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
- if (!fallBackFlag && prevMsg?.options?.nested?.length) {
+ if (prevMsg?.options?.nested?.length) {
const nestedRef = prevMsg.options.nested
const flowStandalone = nestedRef.map((f) => ({
...nestedRef.find((r) => r.refSerialize === f.refSerialize),
@@ -197,12 +211,11 @@ class CoreClass {
return
}
- // 📄🤘(tiene return) [options: capture (boolean)]: Si se tiene option boolean
- if (!fallBackFlag && !prevMsg?.options?.nested?.length) {
+ // 📄🤘(tiene return) Si el mensaje previo implementa capture
+ if (!prevMsg?.options?.nested?.length) {
const typeCapture = typeof prevMsg?.options?.capture
- const valueCapture = prevMsg?.options?.capture
- if (['string', 'boolean'].includes(typeCapture) && valueCapture) {
+ if (typeCapture === 'boolean' && fallBackFlag) {
msgToSend = this.flowClass.find(refToContinue?.ref, true) || []
sendFlow(msgToSend, from)
return
@@ -228,6 +241,7 @@ class CoreClass {
}
/**
+ * @deprecated
* @private
* @param {*} message
* @param {*} ref
diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx
index 0cb1222..29a0c63 100644
--- a/packages/docs/src/routes/docs/flows/index.mdx
+++ b/packages/docs/src/routes/docs/flows/index.mdx
@@ -29,13 +29,16 @@ const flowPrincipal = addKeyword(['hola', 'alo'])
Es importante que el número **vaya acompañado de su prefijo**, en el caso de España "34".
```js
-createBot({
+createBot(
+ {
flow: adapterFlow,
provider: adapterProvider,
database: adapterDB,
- },{
- blackList:['34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX']
- })
+ },
+ {
+ blackList: ['34XXXXXXXXX', '34XXXXXXXXX', '34XXXXXXXXX', '34XXXXXXXXX'],
+ }
+)
```
---
@@ -175,65 +178,74 @@ const flowString = addKeyword('hola')
```
---
+
## endFlow()
-Esta funcion se utliza para finalizar un flujo con dos o más addAnswer. Un ejemplo de uso sería registrar 3 datos de un usuario en 3 preguntas distinas y
+Esta funcion se utliza para finalizar un flujo con dos o más addAnswer. Un ejemplo de uso sería registrar 3 datos de un usuario en 3 preguntas distinas y
que el usuario pueda finalizar por él mismo el flujo.
Como podrás comprobar en el ejemplo siguiente, se puede vincular flowDynamic y todas sus funciones; como por ejemplo botones.
-
-
```js
const flowFormulario = addKeyword(['Hola'])
-
-.addAnswer(['Hola!','Escriba su *Nombre* para generar su solicitud'],
-{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
-async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
- .addAnswer(['También necesito tus dos apellidos'],
- {capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
- async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
- .addAnswer(['Dejeme su número de teléfono y le llamaré lo antes posible.'],
-{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
-async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
-
-
-
+ .addAnswer(
+ ['Hola!', 'Escriba su *Nombre* para generar su solicitud'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
+ .addAnswer(
+ ['También necesito tus dos apellidos'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
+ .addAnswer(
+ ['Dejeme su número de teléfono y le llamaré lo antes posible.'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
```
---
-
-
-
-
# QRPortalWeb
Argumento para asignar nombre y puerto al BOT
```js
-QRPortalWeb({name:BOTNAME, port:3005 });
-
+QRPortalWeb({ name: BOTNAME, port: 3005 })
```
---
-
-
Date: Sat, 28 Jan 2023 16:06:12 +0100
Subject: [PATCH 15/21] fix(cli): :zap: refactor fallback in child flow
---
packages/bot/core/core.class.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js
index 418fef4..b3bc15b 100644
--- a/packages/bot/core/core.class.js
+++ b/packages/bot/core/core.class.js
@@ -143,8 +143,8 @@ class CoreClass {
QueuePrincipal.queue = []
if (next) return continueFlow()
return this.sendProviderAndSave(from, {
- ...refToContinue,
- answer: message ?? refToContinue.answer,
+ ...prevMsg,
+ answer: message ?? prevMsg.answer,
})
}
From f95331d3dc70e76a3dfbe4c8d24059f0e7a164ef Mon Sep 17 00:00:00 2001
From: Leifer Mendez
Date: Sat, 28 Jan 2023 16:25:22 +0100
Subject: [PATCH 16/21] feat(provider): :zap: venom wweb
---
package.json | 1 -
packages/docs/src/routes/docs/flows/index.mdx | 98 +++++++++++--------
.../provider/src/web-whatsapp/package.json | 2 +-
yarn.lock | 50 +---------
4 files changed, 59 insertions(+), 92 deletions(-)
diff --git a/package.json b/package.json
index 859f059..2ad9893 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,6 @@
"eslint-config-prettier": "^8.5.0",
"fs-extra": "^11.1.0",
"git-cz": "^4.9.0",
- "got": "11.8.3",
"husky": "^8.0.2",
"mime-types": "^2.1.35",
"only-allow": "^1.1.1",
diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx
index 0cb1222..29a0c63 100644
--- a/packages/docs/src/routes/docs/flows/index.mdx
+++ b/packages/docs/src/routes/docs/flows/index.mdx
@@ -29,13 +29,16 @@ const flowPrincipal = addKeyword(['hola', 'alo'])
Es importante que el número **vaya acompañado de su prefijo**, en el caso de España "34".
```js
-createBot({
+createBot(
+ {
flow: adapterFlow,
provider: adapterProvider,
database: adapterDB,
- },{
- blackList:['34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX','34XXXXXXXXX']
- })
+ },
+ {
+ blackList: ['34XXXXXXXXX', '34XXXXXXXXX', '34XXXXXXXXX', '34XXXXXXXXX'],
+ }
+)
```
---
@@ -175,65 +178,74 @@ const flowString = addKeyword('hola')
```
---
+
## endFlow()
-Esta funcion se utliza para finalizar un flujo con dos o más addAnswer. Un ejemplo de uso sería registrar 3 datos de un usuario en 3 preguntas distinas y
+Esta funcion se utliza para finalizar un flujo con dos o más addAnswer. Un ejemplo de uso sería registrar 3 datos de un usuario en 3 preguntas distinas y
que el usuario pueda finalizar por él mismo el flujo.
Como podrás comprobar en el ejemplo siguiente, se puede vincular flowDynamic y todas sus funciones; como por ejemplo botones.
-
-
```js
const flowFormulario = addKeyword(['Hola'])
-
-.addAnswer(['Hola!','Escriba su *Nombre* para generar su solicitud'],
-{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
-async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
- .addAnswer(['También necesito tus dos apellidos'],
- {capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
- async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
- .addAnswer(['Dejeme su número de teléfono y le llamaré lo antes posible.'],
-{capture: true,buttons:[{body:'❌ Cancelar solicitud'}]},
-async (ctx,{flowDynamic, endFlow})=>{
- if(ctx.body == '❌ Cancelar solicitud'){
- await flowDynamic([{body: "❌ *Su solicitud de cita ha sido cancelada* ❌", buttons:[{body:'⬅️ Volver al Inicio'}]}])
- return endFlow()
- }
- })
-
-
-
+ .addAnswer(
+ ['Hola!', 'Escriba su *Nombre* para generar su solicitud'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
+ .addAnswer(
+ ['También necesito tus dos apellidos'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
+ .addAnswer(
+ ['Dejeme su número de teléfono y le llamaré lo antes posible.'],
+ { capture: true, buttons: [{ body: '❌ Cancelar solicitud' }] },
+ async (ctx, { flowDynamic, endFlow }) => {
+ if (ctx.body == '❌ Cancelar solicitud') {
+ await flowDynamic([
+ {
+ body: '❌ *Su solicitud de cita ha sido cancelada* ❌',
+ buttons: [{ body: '⬅️ Volver al Inicio' }],
+ },
+ ])
+ return endFlow()
+ }
+ }
+ )
```
---
-
-
-
-
# QRPortalWeb
Argumento para asignar nombre y puerto al BOT
```js
-QRPortalWeb({name:BOTNAME, port:3005 });
-
+QRPortalWeb({ name: BOTNAME, port: 3005 })
```
---
-
-
Date: Sat, 28 Jan 2023 16:44:30 +0100
Subject: [PATCH 17/21] feat(provider): :zap: venom wweb
---
packages/bot/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/bot/package.json b/packages/bot/package.json
index fe542c1..30211e4 100644
--- a/packages/bot/package.json
+++ b/packages/bot/package.json
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
- "version": "0.0.73-alpha.0",
+ "version": "0.0.84-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {
From 1c66f178a56d284bb8cb9df5ca17685c7e5d1ddd Mon Sep 17 00:00:00 2001
From: Leifer Mendez
Date: Sat, 28 Jan 2023 18:41:58 +0100
Subject: [PATCH 18/21] fix(cli): :zap: endflow
---
__test__/06-case.test.js | 111 ++++++++++++++++++++++++++++++++
packages/bot/core/core.class.js | 11 +++-
packages/bot/package.json | 2 +-
3 files changed, 120 insertions(+), 4 deletions(-)
create mode 100644 __test__/06-case.test.js
diff --git a/__test__/06-case.test.js b/__test__/06-case.test.js
new file mode 100644
index 0000000..c68679e
--- /dev/null
+++ b/__test__/06-case.test.js
@@ -0,0 +1,111 @@
+const { test } = require('uvu')
+const assert = require('uvu/assert')
+const MOCK_DB = require('../packages/database/src/mock')
+const PROVIDER_DB = require('../packages/provider/src/mock')
+const {
+ addKeyword,
+ createBot,
+ createFlow,
+ createProvider,
+} = require('../packages/bot/index')
+
+/**
+ * Falsear peticion async
+ * @param {*} fakeData
+ * @returns
+ */
+const fakeHTTP = async (fakeData = []) => {
+ await delay(5)
+ const data = fakeData.map((u, i) => ({ body: `${i + 1} ${u}` }))
+ return Promise.resolve(data)
+}
+
+test(`[Caso - 06] Finalizar Flujo (endFlow)`, async () => {
+ const MOCK_VALUES = [
+ '¿CUal es tu email?',
+ 'Continuamos....',
+ '¿Cual es tu edad?',
+ ]
+ const provider = createProvider(PROVIDER_DB)
+ const database = new MOCK_DB()
+
+ const flujoPrincipal = addKeyword(['hola'])
+ .addAnswer(
+ MOCK_VALUES[0],
+ {
+ capture: true,
+ },
+ async (ctx, { flowDynamic, fallBack }) => {
+ const validation = ctx.body.includes('@')
+
+ if (validation) {
+ const getDataFromApi = await fakeHTTP([
+ 'Gracias por tu email se ha validado de manera correcta',
+ ])
+ return flowDynamic(getDataFromApi)
+ }
+ return fallBack(validation)
+ }
+ )
+ .addAnswer(MOCK_VALUES[1], null, async (_, { endFlow }) => {
+ return endFlow()
+ })
+ .addAnswer(
+ MOCK_VALUES[2],
+ { capture: true },
+ async (ctx, { flowDynamic, fallBack }) => {
+ if (ctx.body !== '18') {
+ await delay(50)
+ return fallBack(false, 'Ups creo que no eres mayor de edad')
+ }
+ return flowDynamic('Bien tu edad es correcta!')
+ }
+ )
+ .addAnswer('Puedes pasar')
+
+ createBot({
+ database,
+ flow: createFlow([flujoPrincipal]),
+ provider,
+ })
+
+ provider.delaySendMessage(0, 'message', {
+ from: '000',
+ body: 'hola',
+ })
+
+ provider.delaySendMessage(10, 'message', {
+ from: '000',
+ body: 'this is not email value',
+ })
+
+ provider.delaySendMessage(20, 'message', {
+ from: '000',
+ body: 'test@test.com',
+ })
+
+ provider.delaySendMessage(90, 'message', {
+ from: '000',
+ body: '20',
+ })
+
+ await delay(1200)
+ const getHistory = database.listHistory.map((i) => i.answer)
+ assert.is(MOCK_VALUES[0], getHistory[0])
+ assert.is('this is not email value', getHistory[1])
+ assert.is(MOCK_VALUES[0], getHistory[2])
+ assert.is('test@test.com', getHistory[3])
+ assert.is(
+ '1 Gracias por tu email se ha validado de manera correcta',
+ getHistory[4]
+ )
+ assert.is(MOCK_VALUES[1], getHistory[5])
+ assert.is('20', getHistory[6])
+ assert.is(undefined, getHistory[7])
+})
+
+test.run()
+
+function delay(ms) {
+ return new Promise((res) => setTimeout(res, ms))
+}
diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js
index b3bc15b..90340e6 100644
--- a/packages/bot/core/core.class.js
+++ b/packages/bot/core/core.class.js
@@ -98,10 +98,15 @@ class CoreClass {
}
// 📄 Finalizar flujo
- const endFlow = async () => {
+ const endFlow = async (message = null) => {
prevMsg = null
endFlowFlag = true
clearQueue()
+ if (message)
+ this.sendProviderAndSave(from, {
+ ...prevMsg,
+ answer: message ?? prevMsg.answer,
+ })
return
}
@@ -199,7 +204,7 @@ class CoreClass {
}
// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
- if (prevMsg?.options?.nested?.length) {
+ if (!endFlowFlag && prevMsg?.options?.nested?.length) {
const nestedRef = prevMsg.options.nested
const flowStandalone = nestedRef.map((f) => ({
...nestedRef.find((r) => r.refSerialize === f.refSerialize),
@@ -212,7 +217,7 @@ class CoreClass {
}
// 📄🤘(tiene return) Si el mensaje previo implementa capture
- if (!prevMsg?.options?.nested?.length) {
+ if (!endFlowFlag && !prevMsg?.options?.nested?.length) {
const typeCapture = typeof prevMsg?.options?.capture
if (typeCapture === 'boolean' && fallBackFlag) {
diff --git a/packages/bot/package.json b/packages/bot/package.json
index 30211e4..827194b 100644
--- a/packages/bot/package.json
+++ b/packages/bot/package.json
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
- "version": "0.0.84-alpha.0",
+ "version": "0.0.86-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {
From b655ae449e7958ea940d8cc3c678fd66f60b6385 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leifer=20Jes=C3=BAs=20Mendez?=
Date: Sun, 29 Jan 2023 12:46:31 +0100
Subject: [PATCH 19/21] fix(bot): :fire: endFlow with ctx
---
packages/bot/core/core.class.js | 48 ++++++++++++++++++---------------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js
index b3bc15b..9ddf444 100644
--- a/packages/bot/core/core.class.js
+++ b/packages/bot/core/core.class.js
@@ -91,6 +91,25 @@ class CoreClass {
this.databaseClass.save(ctxByNumber)
}
+ // 📄 Crar CTX de mensaje (uso private)
+ const createCtxMessage = (payload = {}, index = 0) => {
+ const body =
+ typeof payload === 'string'
+ ? payload
+ : payload?.body ?? payload?.answer
+ const media = payload?.media ?? null
+ const buttons = payload?.buttons ?? []
+ const capture = payload?.capture ?? false
+
+ return toCtx({
+ body,
+ from,
+ keyword: null,
+ index,
+ options: { media, buttons, capture },
+ })
+ }
+
// 📄 Limpiar cola de procesos
const clearQueue = () => {
QueuePrincipal.pendingPromise = false
@@ -98,9 +117,12 @@ class CoreClass {
}
// 📄 Finalizar flujo
- const endFlow = async () => {
+ const endFlow = async (message = null) => {
prevMsg = null
endFlowFlag = true
+ if (message)
+ this.sendProviderAndSave(from, createCtxMessage(message))
+
clearQueue()
return
}
@@ -151,28 +173,12 @@ class CoreClass {
// 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes
// para evitar bloque de whatsapp
- const flowDynamic = async (
- listMsg = [],
- optListMsg = { limit: 5, fallback: false }
- ) => {
+ const flowDynamic = async (listMsg = []) => {
if (!Array.isArray(listMsg)) listMsg = [listMsg]
- fallBackFlag = optListMsg.fallback
- const parseListMsg = listMsg
- .map((opt, index) => {
- const body = typeof opt === 'string' ? opt : opt.body
- const media = opt?.media ?? null
- const buttons = opt?.buttons ?? []
-
- return toCtx({
- body,
- from,
- keyword: null,
- index,
- options: { media, buttons },
- })
- })
- .slice(0, optListMsg.limit)
+ const parseListMsg = listMsg.map((opt, index) =>
+ createCtxMessage(opt, index)
+ )
if (endFlowFlag) return
for (const msg of parseListMsg) {
From f6114affadfbc324536a86167d1fdfe8da3c8de6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Leifer=20Jes=C3=BAs=20Mendez?=
Date: Sun, 29 Jan 2023 13:39:09 +0100
Subject: [PATCH 20/21] fix(bot): :fire: endFlow with ctx
---
packages/bot/core/core.class.js | 9 ++++++++-
packages/bot/package.json | 2 +-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js
index 9ddf444..60644a5 100644
--- a/packages/bot/core/core.class.js
+++ b/packages/bot/core/core.class.js
@@ -166,7 +166,14 @@ class CoreClass {
if (next) return continueFlow()
return this.sendProviderAndSave(from, {
...prevMsg,
- answer: message ?? prevMsg.answer,
+ answer:
+ typeof message === 'string'
+ ? message
+ : message?.body ?? prevMsg.answer,
+ options: {
+ ...prevMsg.options,
+ buttons: message?.buttons ?? prevMsg.options?.buttons,
+ },
})
}
diff --git a/packages/bot/package.json b/packages/bot/package.json
index 30211e4..5d2dc0c 100644
--- a/packages/bot/package.json
+++ b/packages/bot/package.json
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
- "version": "0.0.84-alpha.0",
+ "version": "0.0.89-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {
From f7d90efc2f48dad8fed3cbd21b2578ad296c2bd6 Mon Sep 17 00:00:00 2001
From: Leifer Mendez
Date: Sun, 29 Jan 2023 18:33:32 +0100
Subject: [PATCH 21/21] chore(release): 0.1.19
---
CHANGELOG.md | 30 ++++++++++++++++++++++++++++++
package.json | 2 +-
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b39939..d0bdbfa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,36 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+### [0.1.19](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.18...v0.1.19) (2023-01-29)
+
+
+### Features
+
+* :fire: bailey add media ([eab39e4](https://github.com/leifermendez/bot-whatsapp/commit/eab39e4ac06fd46f1a4671f8c15d1456b4400b97))
+* :zap: more feature ([e19c3a2](https://github.com/leifermendez/bot-whatsapp/commit/e19c3a25a40259c74b4add9635af4844907eed26))
+* **provider:** :rocket: fix issues in providers venom and wwebjs ([cbe438b](https://github.com/leifermendez/bot-whatsapp/commit/cbe438b77854e8df48b9dafaf7a837d21124ac5f))
+* **provider:** :rocket: fix provider ([0ad4c58](https://github.com/leifermendez/bot-whatsapp/commit/0ad4c58457b548dc41c0f9e8470d59c48de7b95a))
+* **provider:** :rocket: fix provider ([f8c7184](https://github.com/leifermendez/bot-whatsapp/commit/f8c7184487065443ab10f77aaf585e8bd63ca441))
+* **provider:** :rocket: fix provider ([b2afa45](https://github.com/leifermendez/bot-whatsapp/commit/b2afa45352a7ab1f5d9775f3c1fde475bd8ca204))
+* **provider:** :rocket: fix provider venom and wwebjs ([dcb0566](https://github.com/leifermendez/bot-whatsapp/commit/dcb0566d2bc3da40cd0c71554bb5ea0ec115d9ca))
+* **provider:** :rocket: implements all send media to venom provider ([9dd7c02](https://github.com/leifermendez/bot-whatsapp/commit/9dd7c02b6a5474aff063f7d6be0ca8519504b93c))
+* **provider:** :rocket: send file wwebjs ([6ff1a3a](https://github.com/leifermendez/bot-whatsapp/commit/6ff1a3a980196c01c66ed04ee07d0e7e57256504))
+* **provider:** :zap: bailey add send file video audio ([14d1a61](https://github.com/leifermendez/bot-whatsapp/commit/14d1a61fa259c09135c37c55bd79e97c9c8367e4))
+* **provider:** :zap: venom wweb ([fd2847a](https://github.com/leifermendez/bot-whatsapp/commit/fd2847aea0db17a0bdf33b5bca67a4cb8db2da16))
+* **provider:** :zap: venom wweb ([f95331d](https://github.com/leifermendez/bot-whatsapp/commit/f95331d3dc70e76a3dfbe4c8d24059f0e7a164ef))
+* **provider:** 🚀 implements all send media to venom provider ([bd7d150](https://github.com/leifermendez/bot-whatsapp/commit/bd7d150c047af41fdbb47f0a50a21e82cd79ee85))
+
+
+### Bug Fixes
+
+* **bot:** :fire: endFlow with ctx ([f6114af](https://github.com/leifermendez/bot-whatsapp/commit/f6114affadfbc324536a86167d1fdfe8da3c8de6))
+* **bot:** :fire: endFlow with ctx ([b655ae4](https://github.com/leifermendez/bot-whatsapp/commit/b655ae449e7958ea940d8cc3c678fd66f60b6385))
+* **bot:** :zap: endFlow butons ([87a4203](https://github.com/leifermendez/bot-whatsapp/commit/87a4203cd5b88f566387a76d586248e4265d6e4e))
+* **bot:** :zap: fix fallback refactor ([e22780d](https://github.com/leifermendez/bot-whatsapp/commit/e22780d3faba94f71a70f1f201a20690608fa5bf))
+* **cli:** :zap: endflow ([1c66f17](https://github.com/leifermendez/bot-whatsapp/commit/1c66f178a56d284bb8cb9df5ca17685c7e5d1ddd))
+* **cli:** :zap: refactor fallback in child flow ([b33e346](https://github.com/leifermendez/bot-whatsapp/commit/b33e34692d3abcb6874308a9be79f74be4a2c3a8))
+* **cli:** :zap: refactor fallback in child flow ([8da4b20](https://github.com/leifermendez/bot-whatsapp/commit/8da4b204b41125b5d0fa0aee4fa87c1f5faf5568))
+
### [0.1.18](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.17...v0.1.18) (2023-01-24)
diff --git a/package.json b/package.json
index 2ad9893..30e3cf4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/root",
- "version": "0.1.18",
+ "version": "0.1.19",
"description": "Bot de wahtsapp open source para MVP o pequeños negocios",
"main": "app.js",
"private": true,