diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index 6e7d06ea2..5cf16f00d 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -19,6 +19,7 @@ const loggerQueue = new Console({ }) const idleForCallback = new IdleState() +const DynamicBlacklist = require('../utils/BlacklistDynamic') /** * [ ] Escuchar eventos del provider asegurarte que los provider emitan eventos @@ -33,6 +34,7 @@ class CoreClass extends EventEmitter { queuePrincipal stateHandler = new SingleState() globalStateHandler = new GlobalState() + dynamicBlacklist = new DynamicBlacklist() generalArgs = { blackList: [], listEvents: {}, @@ -51,6 +53,8 @@ class CoreClass extends EventEmitter { this.providerClass = _provider this.generalArgs = { ...this.generalArgs, ..._args } + this.dynamicBlacklist.addToBlacklist(this.generalArgs.blackList) + this.queuePrincipal = new Queue( loggerQueue, this.generalArgs.queue.concurrencyLimit, @@ -108,7 +112,7 @@ class CoreClass extends EventEmitter { let msgToSend = [] let endFlowFlag = false let fallBackFlag = false - if (this.generalArgs.blackList.includes(from)) return + if (this.dynamicBlacklist.isInBlacklist(from)) return if (!body) return let prevMsg = await this.databaseClass.getPrevByNumber(from) diff --git a/packages/bot/utils/BlacklistDynamic.js b/packages/bot/utils/BlacklistDynamic.js new file mode 100644 index 000000000..693ff951a --- /dev/null +++ b/packages/bot/utils/BlacklistDynamic.js @@ -0,0 +1,80 @@ +class DynamicBlacklist { + #blacklist = new Set() + + /** + * Constructor para inicializar la lista negra. + * @param {Array} initialNumbers - Lista inicial de números a bloquear. + */ + constructor(initialNumbers = []) { + this.addToBlacklist(initialNumbers) + } + + /** + * Excepción lanzada cuando un número ya existe en la lista negra. + */ + static PhoneNumberAlreadyExistsError = class extends Error { + constructor(phoneNumber) { + super(`El número de teléfono ${phoneNumber} ya está en la lista negra.`) + this.name = 'PhoneNumberAlreadyExistsError' + } + } + + /** + * Excepción lanzada cuando un número no se encuentra en la lista negra. + */ + static PhoneNumberNotFoundError = class extends Error { + constructor(phoneNumber) { + super(`El número de teléfono ${phoneNumber} no está en la lista negra.`) + this.name = 'PhoneNumberNotFoundError' + } + } + + /** + * Añade uno o varios números de teléfono a la lista negra. + * @param {string | Array} phoneNumbers - Número o números a añadir. + * @returns {Array} - Devuelve una lista de mensajes indicando el resultado de añadir cada número. + */ + addToBlacklist(...phoneNumbers) { + const responseMessages = [] + + phoneNumbers.flat().forEach((number) => { + if (this.#blacklist.has(number)) { + responseMessages.push(`El número de teléfono ${number} ya está en la lista negra.`) + } else { + this.#blacklist.add(number) + responseMessages.push(`Número ${number} añadido exitosamente.`) + } + }) + + return responseMessages + } + + /** + * Elimina un número de teléfono de la lista negra. + * @param {string} phoneNumber - El número a eliminar. + */ + removeFromBlacklist(phoneNumber) { + if (!this.#blacklist.has(phoneNumber)) { + throw new DynamicBlacklist.PhoneNumberNotFoundError(phoneNumber) + } + this.#blacklist.delete(phoneNumber) + } + + /** + * Verifica si un número de teléfono está en la lista negra. + * @param {string} phoneNumber - El número a verificar. + * @returns {boolean} - Verdadero si está en la lista, falso en caso contrario. + */ + isInBlacklist(phoneNumber) { + return this.#blacklist.has(phoneNumber) + } + + /** + * Proporciona una copia de la lista negra actual. + * @returns {Array} - Los números de teléfono en la lista negra. + */ + getBlacklistSnapshot() { + return [...this.#blacklist] + } +} +module.exports = DynamicBlacklist diff --git a/packages/docs/src/root.tsx b/packages/docs/src/root.tsx index 87f374485..148235f2d 100644 --- a/packages/docs/src/root.tsx +++ b/packages/docs/src/root.tsx @@ -47,6 +47,7 @@ export default component$(() => { { name: 'fallBack', link: '/docs/fall-back' }, { name: 'endFlow', link: '/docs/end-flow' }, { name: 'gotoFlow', link: '/docs/goto-flow' }, + { name: 'idle', link: '/docs/idle' }, { name: 'blacklist', link: '/docs/blacklist' }, ], }, diff --git a/packages/docs/src/routes/docs/idle/index.mdx b/packages/docs/src/routes/docs/idle/index.mdx new file mode 100644 index 000000000..7a539c2c8 --- /dev/null +++ b/packages/docs/src/routes/docs/idle/index.mdx @@ -0,0 +1,45 @@ +import Navigation from '../../../components/widgets/Navigation' + +# idle + +Esta funcionalidad te permite dada una cantidad de tiempo de inactividad en el chat, ejecutar una acción. + +## Ejemplo + +En el siguiente ejemplo, si el usuario no responde en 2 segundos, se ejecutará la acción de cancelar el flujo. + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flujoFinal = addKeyword(EVENTS.ACTION).addAnswer('Se canceló por inactividad') + +const flujoPrincipal = addKeyword(['hola']) + .addAnswer( + 'Debes de responder antes de que transcurran 2 segundos', + { capture: true, idle: 2000 }, // idle: 2000 = 2 segundos + async (ctx, { gotoFlow, inRef }) => { + if (ctx?.idleFallBack) { + return gotoFlow(flujoFinal) + } + } + ) + .addAnswer('gracias!') + +``` + +## API + +### Propiedades + +- **idle** - Tiempo de inactividad en milisegundos +- **idleFallBack** - Si se ejecutó la acción por inactividad + + +--- + + diff --git a/packages/docs/src/services/github.ts b/packages/docs/src/services/github.ts index 1a06380fb..f4f2893df 100644 --- a/packages/docs/src/services/github.ts +++ b/packages/docs/src/services/github.ts @@ -11,18 +11,13 @@ export const fetchGithub = async (token: string) => { Authorization: `Bearer ${token}`, }, }) - const listUsers = await data.json() + try { + const listUsers = await data.json() return listUsers.map((u: any) => ({ ...u, avatar_url: `${u.avatar_url}&s=80`, })) - // try { - // const listUsers = await data.json() - // return listUsers.map((u: any) => ({ - // ...u, - // avatar_url: `${u.avatar_url}&s=80`, - // })) - // } catch (error) { - // return [] - // } + } catch (error) { + return [] + } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f72bc570..4e08fc69d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,39 @@ importers: specifier: ^0.5.6 version: 0.5.6 + base-meta-memory: + dependencies: + '@bot-whatsapp/bot': + specifier: 0.0.197-alpha.0 + version: 0.0.197-alpha.0 + '@bot-whatsapp/cli': + specifier: latest + version: 0.1.33 + '@bot-whatsapp/database': + specifier: latest + version: 0.1.33 + '@bot-whatsapp/provider': + specifier: latest + version: 0.1.33 + async: + specifier: ^3.2.4 + version: 3.2.4 + axios: + specifier: ^1.2.1 + version: 1.4.0 + body-parser: + specifier: ^1.20.1 + version: 1.20.1 + form-data: + specifier: ^4.0.0 + version: 4.0.0 + polka: + specifier: ^0.5.2 + version: 0.5.2 + queue-promise: + specifier: ^2.2.1 + version: 2.2.1 + packages/bot: dependencies: dotenv: @@ -1245,6 +1278,68 @@ packages: } dev: true + /@bot-whatsapp/bot@0.0.197-alpha.0: + resolution: + { + integrity: sha512-FRxVQ8rNPzUkxrye6jSHeVBrDicwK2h5jJtHoHye4Y2QTulUmAFJbwOJ6tvk5Cg/7okXuXurKSLYEGYALywNrA==, + } + dependencies: + dotenv: 16.3.1 + dev: false + + /@bot-whatsapp/bot@0.1.33: + resolution: + { + integrity: sha512-PHM4pe0wx8IUipL37O+rcx2a36HMBzgPQt7Sto3EH7Fndqj7bwsmmhKTzAtGDsja4NOlecjz2bh8fjC1aI9Faw==, + } + dependencies: + dotenv: 16.3.1 + dev: false + + /@bot-whatsapp/cli@0.1.33: + resolution: + { + integrity: sha512-DkHZVlowAZAqXestrMcplCJzRYiHFu54TpCvR/nXlOzz/g4UfqT3lcZGb6mm28Jc8HxTTAVnwCnjKnNZSaht/Q==, + } + hasBin: true + dependencies: + picocolors: 1.0.0 + dev: false + + /@bot-whatsapp/database@0.1.33: + resolution: + { + integrity: sha512-rw5XdHumhh14UJlWh3PzTLgVyTFwZigl5etwpNXI3u7n8zyorHSg8NCJou3sOlTTJld4f+85OpfiZrOeiBMaYQ==, + } + dependencies: + dotenv: 16.3.1 + mongodb: 4.11.0 + mysql2: 2.3.3 + pg: 8.11.2 + transitivePeerDependencies: + - aws-crt + - pg-native + dev: false + + /@bot-whatsapp/provider@0.1.33: + resolution: + { + integrity: sha512-GHLNd9UWdipB6QeB2+hGP5wOzyI0NwPvzXi/gex7kkaHjARxGWYorAxit4Mj6dh12gvY9zTDIh91JWNgj6ABog==, + } + dependencies: + '@bot-whatsapp/bot': 0.1.33 + '@ffmpeg-installer/ffmpeg': 1.1.0 + axios: 1.4.0 + combine-image: 1.0.3 + fluent-ffmpeg: 2.1.2 + follow-redirects: 1.15.2 + qr-image: 3.2.0 + rimraf: 3.0.2 + sharp: 0.30.5 + transitivePeerDependencies: + - debug + dev: false + /@bugsnag/browser@7.21.0: resolution: { @@ -5064,6 +5159,7 @@ packages: { integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==, } + dev: true /@types/node@20.4.7: resolution: @@ -5077,7 +5173,6 @@ packages: { integrity: sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==, } - dev: true /@types/normalize-package-data@2.4.1: resolution: @@ -5226,7 +5321,7 @@ packages: integrity: sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==, } dependencies: - '@types/node': 18.11.18 + '@types/node': 20.5.7 '@types/webidl-conversions': 7.0.0 dev: false @@ -6471,7 +6566,7 @@ packages: integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==, } dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -6716,7 +6811,6 @@ packages: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - dev: true /boolbase@1.0.0: resolution: @@ -6993,7 +7087,6 @@ packages: integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==, } engines: { node: '>= 0.8' } - dev: true /c8@7.13.0: resolution: @@ -7133,7 +7226,6 @@ packages: dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.1 - dev: true /callsite@1.0.0: resolution: @@ -7982,7 +8074,6 @@ packages: integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, } engines: { node: '>= 0.6' } - dev: true /conventional-changelog-angular@5.0.13: resolution: @@ -9156,7 +9247,6 @@ packages: integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==, } engines: { node: '>= 0.8' } - dev: true /deprecation@2.3.1: resolution: @@ -9186,7 +9276,6 @@ packages: integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, } engines: { node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16 } - dev: true /detect-indent@6.1.0: resolution: @@ -9589,7 +9678,6 @@ packages: integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==, } engines: { node: '>=12' } - dev: true /dotgitignore@2.1.0: resolution: @@ -11382,6 +11470,19 @@ packages: from2: 2.3.0 dev: true + /follow-redirects@1.15.2: + resolution: + { + integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==, + } + engines: { node: '>=4.0' } + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /follow-redirects@1.15.2(debug@4.3.4): resolution: { @@ -11693,7 +11794,6 @@ packages: { integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==, } - dev: true /function.prototype.name@1.1.5: resolution: @@ -11797,7 +11897,6 @@ packages: has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 - dev: true /get-own-enumerable-property-symbols@3.0.2: resolution: @@ -12466,7 +12565,6 @@ packages: integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==, } engines: { node: '>= 0.4' } - dev: true /has-symbol-support-x@1.4.2: resolution: @@ -12481,7 +12579,6 @@ packages: integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, } engines: { node: '>= 0.4' } - dev: true /has-to-string-tag-x@1.4.1: resolution: @@ -12576,7 +12673,6 @@ packages: engines: { node: '>= 0.4.0' } dependencies: function-bind: 1.1.1 - dev: true /hasbin@1.2.3: resolution: @@ -12778,7 +12874,6 @@ packages: setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 - dev: true /http-proxy-agent@4.0.1: resolution: @@ -12926,7 +13021,6 @@ packages: engines: { node: '>=0.10.0' } dependencies: safer-buffer: 2.1.2 - dev: true /iconv-lite@0.6.3: resolution: @@ -15456,7 +15550,6 @@ packages: integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==, } engines: { node: '>= 0.6' } - dev: true /memoize-one@6.0.0: resolution: @@ -16960,7 +17053,6 @@ packages: { integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==, } - dev: true /object-is@1.1.5: resolution: @@ -17039,7 +17131,6 @@ packages: engines: { node: '>= 0.8' } dependencies: ee-first: 1.1.1 - dev: true /on-headers@1.0.2: resolution: @@ -18972,7 +19063,6 @@ packages: engines: { node: '>=0.6' } dependencies: side-channel: 1.0.4 - dev: true /qs@6.11.2: resolution: @@ -19018,6 +19108,14 @@ packages: } dev: true + /queue-promise@2.2.1: + resolution: + { + integrity: sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==, + } + engines: { node: '>=8.12.0' } + dev: false + /quick-lru@4.0.1: resolution: { @@ -19067,7 +19165,6 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: true /raw-body@2.5.2: resolution: @@ -20183,7 +20280,6 @@ packages: { integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==, } - dev: true /sharp@0.30.5: resolution: @@ -20248,7 +20344,6 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.2.1 object-inspect: 1.12.3 - dev: true /sift@7.0.1: resolution: @@ -20752,7 +20847,6 @@ packages: integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==, } engines: { node: '>= 0.8' } - dev: true /stop-iteration-iterator@1.0.0: resolution: @@ -21726,7 +21820,6 @@ packages: integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, } engines: { node: '>=0.6' } - dev: true /toml@3.0.0: resolution: @@ -21944,12 +22037,14 @@ packages: { integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, } + requiresBuild: true /tslib@2.6.2: resolution: { integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==, } + requiresBuild: true /tsutils@3.21.0(typescript@4.8.4): resolution: @@ -22127,7 +22222,6 @@ packages: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - dev: true /typed-array-buffer@1.0.0: resolution: @@ -22478,7 +22572,6 @@ packages: integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, } engines: { node: '>= 0.8' } - dev: true /unset-value@1.0.0: resolution: @@ -22683,6 +22776,7 @@ packages: integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==, } hasBin: true + requiresBuild: true /uuid@9.0.0: resolution: