diff --git a/.eslintignore b/.eslintignore index c6f157a..6c4b500 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ -packages/docs/* \ No newline at end of file +packages/docs/* +packages/portal/* \ No newline at end of file diff --git a/.github/workflows/check-providers.yml b/.github/workflows/check-providers.yml deleted file mode 100644 index 5811dc2..0000000 --- a/.github/workflows/check-providers.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Rev Providers - -on: - pull_request: - branches: - - dev - -jobs: - check-npm: - name: Install Dependencies - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 16.x - cache: 'yarn' - registry-url: https://registry.npmjs.org/ - - - run: corepack enable - - - name: Install NPM Dependencies - run: yarn install --immutable --network-timeout 300000 - - - name: Check Baileys - run: yarn node ./scripts/checker.js --name=baileys --stable=true - - - name: Check Venom - run: yarn node ./scripts/checker.js --name=venom --stable=true - - - name: Check web-whatsapp - run: yarn node ./scripts/checker.js --name=web-whatsapp --stable=true - - - name: Check Meta - run: yarn node ./scripts/checker.js --name=meta --stable=true - - - name: Check Twilio - run: yarn node ./scripts/checker.js --name=twilio --stable=true - - - name: Add and commit changes to gh-pages branch - run: | - git config --local user.email 'action@github.com' - git config --local user.name 'GitHub Action' - git add . - git commit -m 'major' - - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: feature/providers-major diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fd8fa3..56dcd60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: run: yarn install --immutable --network-timeout 300000 - name: Build Package - run: yarn build + run: yarn build:full - name: Build Eslint rules run: yarn lint:fix @@ -56,3 +56,51 @@ jobs: - name: Unit Tests run: yarn test + + ############ UNIT TEST ############ + check-providers: + name: Check Providers Versions + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: 'yarn' + registry-url: https://registry.npmjs.org/ + + - run: corepack enable + + - name: Install NPM Dependencies + run: yarn install --immutable --network-timeout 300000 + + - name: Check Baileys + run: yarn node ./scripts/checker.js --name=baileys --stable=true + + - name: Check Venom + run: yarn node ./scripts/checker.js --name=venom --stable=true + + - name: Check web-whatsapp + run: yarn node ./scripts/checker.js --name=web-whatsapp --stable=true + + - name: Check Meta + run: yarn node ./scripts/checker.js --name=meta --stable=true + + - name: Check Twilio + run: yarn node ./scripts/checker.js --name=twilio --stable=true + + - name: Add and commit changes to gh-pages branch + run: | + git config --local user.email 'action@github.com' + git config --local user.name 'GitHub Action' + git add . + git commit -m 'major' + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: feature/providers-major diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 86178fd..a1fed1b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,7 @@ name: 'CodeQL' on: push: - branches: ['main', dev, next-release] + branches: [release/next] pull_request: # The branches below must be a subset of the branches above branches: ['main'] @@ -22,6 +22,7 @@ on: jobs: analyze: + if: ${{ !github.event.act }} name: Analyze runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 9f9e814..b126e98 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -1,12 +1,8 @@ name: Revisando Colaboradores + on: - push: - branches: - - main - pull_request: - branches: - - dev - types: [closed] + schedule: + - cron: '0 9 * * *' jobs: contrib-readme-job: diff --git a/.github/workflows/netlify-dev.yml b/.github/workflows/netlify-dev.yml index e3e8200..1820da5 100644 --- a/.github/workflows/netlify-dev.yml +++ b/.github/workflows/netlify-dev.yml @@ -13,6 +13,7 @@ on: jobs: ############ DOCUMENTATION BUILD ############ build-documentation: + if: ${{ !github.event.act }} name: Build Package runs-on: ubuntu-latest diff --git a/.github/workflows/netlify.yml b/.github/workflows/netlify.yml index bdb51ab..2dac101 100644 --- a/.github/workflows/netlify.yml +++ b/.github/workflows/netlify.yml @@ -3,12 +3,11 @@ name: 📄 (PROD) Desplegando documentacion on: push: branches: - - main - - next-release + - release/next jobs: ############ DOCUMENTATION BUILD ############ - build-documentation: + build-documentation-prod: name: Build Package runs-on: ubuntu-latest diff --git a/.github/workflows/releases-dev.yml b/.github/workflows/releases-dev.yml index a2d9979..4e5c169 100644 --- a/.github/workflows/releases-dev.yml +++ b/.github/workflows/releases-dev.yml @@ -3,7 +3,7 @@ name: 🚀 (DEV) Liberando versiones on: push: branches: - - next-release + - release/next jobs: ############ RELEASE ############ @@ -27,7 +27,7 @@ jobs: run: yarn install --immutable --network-timeout 300000 - name: Build Package - run: yarn build + run: yarn build:full - name: Release @bot-whatsapp/bot run: yarn node ./scripts/release.js --name=bot --version= --token="${{ secrets.NPM_TOKEN }}" @@ -44,6 +44,12 @@ jobs: - name: Release @bot-whatsapp/provider run: yarn node ./scripts/release.js --name=provider --version= --token="${{ secrets.NPM_TOKEN }}" + - name: Release @bot-whatsapp/contexts + run: yarn node ./scripts/release.js --name=contexts --version= --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/portal + run: yarn node ./scripts/release.js --name=portal --version= --token="${{ secrets.NPM_TOKEN }}" + - name: Commit Versioning & Push changes uses: stefanzweifel/git-auto-commit-action@v4 with: diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index daafe13..d587c64 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -2,12 +2,12 @@ name: 🚀⚡ Liberando versiones on: push: - tags: - - 'v*.*.*' - + branches: + - release/production jobs: ############ RELEASE ############ - release: + release-prod: + if: ${{ !github.event.act }} name: Release runs-on: ubuntu-latest steps: @@ -27,32 +27,53 @@ jobs: - run: corepack enable + - name: Set User + run: git config --global user.email "leifer.contacto@gmail.com" && git config --global user.name "Leifer Mendez" + - name: Install NPM Dependencies run: yarn install --immutable --network-timeout 300000 - - name: Build Package - run: yarn build - - - name: Release @bot-whatsapp/bot - run: yarn node ./scripts/release.js --name=bot --version="${{ steps.vars.outputs.tag }}" --token="${{ secrets.NPM_TOKEN }}" - - - name: Release @bot-whatsapp/cli - run: yarn node ./scripts/release.js --name=cli --version="${{ steps.vars.outputs.tag }}" --token="${{ secrets.NPM_TOKEN }}" - - - name: Release @bot-whatsapp/create-bot-whatsapp - run: yarn node ./scripts/release.js --name=create-bot-whatsapp --version="${{ steps.vars.outputs.tag }}" --token="${{ secrets.NPM_TOKEN }}" - - - name: Release @bot-whatsapp/database - run: yarn node ./scripts/release.js --name=database --version="${{ steps.vars.outputs.tag }}" --token="${{ secrets.NPM_TOKEN }}" - - - name: Release @bot-whatsapp/provider - run: yarn node ./scripts/release.js --name=provider --version="${{ steps.vars.outputs.tag }}" --token="${{ secrets.NPM_TOKEN }}" - - name: Set CHANGELOG run: yarn release + - name: get-npm-version + id: package-version + uses: martinbeentjes/npm-get-version-action@main + + - name: Build Package + run: yarn build:full + + - name: Release @bot-whatsapp/bot + run: yarn node ./scripts/release.js --name=bot --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/cli + run: yarn node ./scripts/release.js --name=cli --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/create-bot-whatsapp + run: yarn node ./scripts/release.js --name=create-bot-whatsapp --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/database + run: yarn node ./scripts/release.js --name=database --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/provider + run: yarn node ./scripts/release.js --name=provider --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/contexts + run: yarn node ./scripts/release.js --name=contexts --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release @bot-whatsapp/portal + run: yarn node ./scripts/release.js --name=portal --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.NPM_TOKEN }}" + + - name: Release Github + run: yarn node ./scripts/github.js --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.OCTO_TOKEN }}" + + - name: 'Run if changes have been detected' + run: | + git add . + git commit -m "chore(version): pre release" + - name: Commit Versioning & Push changes + if: github.event_name == 'push' uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: 'release(version): 🚀 - "${{ steps.vars.outputs.tag }}" release' - branch: dev + commit_message: 'chore(version): launch release 🚀 "${{ steps.package-version.outputs.current-version}}"' diff --git a/.gitignore b/.gitignore index 2a3fcb7..1cc3038 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ mediaSend/* !mediaSend/nota-de-voz.mp3 .env .wwebjs_auth +/session +/session/* +/tokens +/tokens/* packages/cli/config.json config.json .yarnrc.yml @@ -38,3 +42,4 @@ yarn-error.log .npmrc # Local Netlify folder .netlify +.secrets \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dafc64e..8d3865b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,107 @@ 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.17](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.16...v0.1.17) (2023-01-13) + + +### Features + +* mod de starters para habiltar portal ([eceb170](https://github.com/leifermendez/bot-whatsapp/commit/eceb170df03721dca4183b658c863b94fa04bc84)) + + +### Bug Fixes + +* **ci:** pre-release ([aaec075](https://github.com/leifermendez/bot-whatsapp/commit/aaec0751408ab49483d428810d94aaf7d46acb94)) +* correccion en starters app.js para portal QR ([f430380](https://github.com/leifermendez/bot-whatsapp/commit/f430380b4f23d41702395c96c628bf13bf443278)) +* **starters:** :zap: added dockerfile ([230981e](https://github.com/leifermendez/bot-whatsapp/commit/230981e2676361149cb2a99def7f705e75009260)) + +### [0.1.16](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.15...v0.1.16) (2023-01-11) + +### [0.1.15](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.14...v0.1.15) (2023-01-11) + +### [0.1.14](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.13...v0.1.14) (2023-01-11) + +### [0.1.13](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.12...v0.1.13) (2023-01-11) + +### [0.1.12](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.10...v0.1.12) (2023-01-11) + +### [0.1.9-pre](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.9...v0.1.9-pre) (2023-01-10) + +### [0.1.7-pre-1](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-alpha...v0.1.7-pre-1) (2023-01-10) + +### [0.1.7-alpha](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-pre...v0.1.7-alpha) (2023-01-10) + +### [0.1.11](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.10...v0.1.11) (2023-01-11) + +### [0.1.9-pre](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.9...v0.1.9-pre) (2023-01-10) + +### [0.1.7-pre-1](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-alpha...v0.1.7-pre-1) (2023-01-10) + +### [0.1.7-alpha](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-pre...v0.1.7-alpha) (2023-01-10) + +### [0.1.10](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.8...v0.1.10) (2023-01-11) + + +### Bug Fixes + +* :fire: update qr package ([ecde23f](https://github.com/leifermendez/bot-whatsapp/commit/ecde23fdea65def209aa874af35a3f293e6b1a91)) + +### [0.1.8](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-pre...v0.1.8) (2023-01-10) + +### [0.1.7](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.7-pre...v0.1.7) (2023-01-10) + +### [0.1.6](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.5...v0.1.6) (2023-01-10) + + +### Features + +* :zap: new portal web for qr scan ([cb2e869](https://github.com/leifermendez/bot-whatsapp/commit/cb2e8692a3f94c8b24993cd11dd564f094b0e4ef)) +* :zap: new portal web for qr scan ([9e93795](https://github.com/leifermendez/bot-whatsapp/commit/9e93795e6fce38890045389da95184fef1fbe0da)) +* :zap: new portal web for qr scan ([3c178ea](https://github.com/leifermendez/bot-whatsapp/commit/3c178ea113b140535a51f5dcd521dbb66251670e)) +* :zap: new portal web for qr scan ([1f1f564](https://github.com/leifermendez/bot-whatsapp/commit/1f1f564f4e2e3aa13b84de500fe215e0c45c2770)) +* :zap: new portal web for qr scan ([3de5f4b](https://github.com/leifermendez/bot-whatsapp/commit/3de5f4b77a10e30632ff7555f5af5d8e93cb2019)) +* :zap: qr code filename ([d794f60](https://github.com/leifermendez/bot-whatsapp/commit/d794f604ac8a835e523709dbf18c9b1609bbd00e)) +* :zap: qr portal ([246ecdc](https://github.com/leifermendez/bot-whatsapp/commit/246ecdc11a8c4e652867c842b612dc4ce73f9828)) +* :zap: qr portal ([af8b401](https://github.com/leifermendez/bot-whatsapp/commit/af8b401d075e1c35065589ede61476461ce86b4d)) +* agregamos dockerfile y webserver a starters ([f9e3bbc](https://github.com/leifermendez/bot-whatsapp/commit/f9e3bbc6655060408e4fdbe1d7e920c2ed4fca53)) + + +### Bug Fixes + +* :zap: add Dockerfile, starter ([4e0d33c](https://github.com/leifermendez/bot-whatsapp/commit/4e0d33c6bb46ad259774f6d0c38c6c0b5f8ca4a9)) +* :zap: fix inject port args ([20f752e](https://github.com/leifermendez/bot-whatsapp/commit/20f752e6c1b1f7d11948fc4f2f8950f7834df7d9)) +* :zap: fix inject port args ([7a23eb0](https://github.com/leifermendez/bot-whatsapp/commit/7a23eb0cc6f93ec21c5ab34e46981ae7a93f42ff)) +* **provider:** :zap: fix send image baileys ([2ddea54](https://github.com/leifermendez/bot-whatsapp/commit/2ddea5468d235035478d4e91e63c821da19da179)) +* **provider:** :zap: fix send image baileys ([391e11c](https://github.com/leifermendez/bot-whatsapp/commit/391e11ce738cd64792b5237d69f3739b0263c198)) +* **provider:** :zap: fix send image baileys ([5d10cb9](https://github.com/leifermendez/bot-whatsapp/commit/5d10cb9026da60043e9a2f86117ebb04d0631a3f)) +* **provider:** fix error docker as root user ([5a033da](https://github.com/leifermendez/bot-whatsapp/commit/5a033da83aee1f614120bccf27c9f330500cc7b0)) + +### [0.1.4](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.5...v0.1.4) (2023-01-10) + + +### Features + +* :zap: new portal web for qr scan ([cb2e869](https://github.com/leifermendez/bot-whatsapp/commit/cb2e8692a3f94c8b24993cd11dd564f094b0e4ef)) +* :zap: new portal web for qr scan ([9e93795](https://github.com/leifermendez/bot-whatsapp/commit/9e93795e6fce38890045389da95184fef1fbe0da)) +* :zap: new portal web for qr scan ([3c178ea](https://github.com/leifermendez/bot-whatsapp/commit/3c178ea113b140535a51f5dcd521dbb66251670e)) +* :zap: new portal web for qr scan ([1f1f564](https://github.com/leifermendez/bot-whatsapp/commit/1f1f564f4e2e3aa13b84de500fe215e0c45c2770)) +* :zap: new portal web for qr scan ([3de5f4b](https://github.com/leifermendez/bot-whatsapp/commit/3de5f4b77a10e30632ff7555f5af5d8e93cb2019)) +* :zap: qr code filename ([d794f60](https://github.com/leifermendez/bot-whatsapp/commit/d794f604ac8a835e523709dbf18c9b1609bbd00e)) +* :zap: qr portal ([246ecdc](https://github.com/leifermendez/bot-whatsapp/commit/246ecdc11a8c4e652867c842b612dc4ce73f9828)) +* :zap: qr portal ([af8b401](https://github.com/leifermendez/bot-whatsapp/commit/af8b401d075e1c35065589ede61476461ce86b4d)) +* agregamos dockerfile y webserver a starters ([f9e3bbc](https://github.com/leifermendez/bot-whatsapp/commit/f9e3bbc6655060408e4fdbe1d7e920c2ed4fca53)) + + +### Bug Fixes + +* :zap: add Dockerfile, starter ([4e0d33c](https://github.com/leifermendez/bot-whatsapp/commit/4e0d33c6bb46ad259774f6d0c38c6c0b5f8ca4a9)) +* :zap: fix inject port args ([20f752e](https://github.com/leifermendez/bot-whatsapp/commit/20f752e6c1b1f7d11948fc4f2f8950f7834df7d9)) +* :zap: fix inject port args ([7a23eb0](https://github.com/leifermendez/bot-whatsapp/commit/7a23eb0cc6f93ec21c5ab34e46981ae7a93f42ff)) +* **provider:** :zap: fix send image baileys ([2ddea54](https://github.com/leifermendez/bot-whatsapp/commit/2ddea5468d235035478d4e91e63c821da19da179)) +* **provider:** :zap: fix send image baileys ([391e11c](https://github.com/leifermendez/bot-whatsapp/commit/391e11ce738cd64792b5237d69f3739b0263c198)) +* **provider:** :zap: fix send image baileys ([5d10cb9](https://github.com/leifermendez/bot-whatsapp/commit/5d10cb9026da60043e9a2f86117ebb04d0631a3f)) +* **provider:** fix error docker as root user ([5a033da](https://github.com/leifermendez/bot-whatsapp/commit/5a033da83aee1f614120bccf27c9f330500cc7b0)) + ### [0.1.3](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.2...v0.1.3) (2023-01-04) diff --git a/package.json b/package.json index 72109ae..354bc44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/root", - "version": "0.1.3", + "version": "0.1.17", "description": "Bot de wahtsapp open source para MVP o pequeños negocios", "main": "app.js", "private": true, @@ -13,12 +13,15 @@ "contexts:rollup": "rollup --config ./packages/contexts/rollup-contexts.config.js", "database:rollup": "rollup --config ./packages/database/rollup-database.config.js", "create-bot-whatsapp:rollup": "rollup --config ./packages/create-bot-whatsapp/rollup-create.config.js", + "portal:rollup": "rollup --config ./packages/portal/rollup-portal.config.js", "format:check": "prettier --check ./packages", "format:write": "prettier --write ./packages", "fmt.staged": "pretty-quick --staged", "lint:check": "eslint ./packages", "lint:fix": "eslint --fix ./packages", - "build": "yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run contexts:rollup && yarn run create-bot-whatsapp:rollup", + "build:portal-web": "cd ./packages/portal/ && yarn run build.types && yarn run build.client && yarn run build.server && yarn run lint --fix", + "build:full": "yarn run build:portal-web && yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run contexts:rollup && yarn run create-bot-whatsapp:rollup && yarn run portal:rollup", + "build": "yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run contexts:rollup && yarn run create-bot-whatsapp:rollup && yarn run portal:rollup", "copy.lib": "node ./scripts/move.js", "test.unit": "node ./node_modules/uvu/bin.js packages test", "test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit", @@ -39,6 +42,7 @@ "packages/database", "packages/provider", "packages/contexts", + "packages/portal", "packages/docs" ], "keywords": [ @@ -63,6 +67,7 @@ "devDependencies": { "@commitlint/cli": "^17.3.0", "@commitlint/config-conventional": "^17.3.0", + "@octokit/core": "^4.1.0", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-json": "^5.0.1", "@rollup/plugin-node-resolve": "^15.0.1", diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index 7550dd0..79d996b 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -8,6 +8,9 @@ const { createWriteStream } = require('fs') const logger = new Console({ stdout: createWriteStream(`${process.cwd()}/core.class.log`), }) + +const QueuePrincipal = new Queue() + /** * [ ] Escuchar eventos del provider asegurarte que los provider emitan eventos * [ ] Guardar historial en db @@ -84,20 +87,40 @@ class CoreClass { this.databaseClass.save(ctxByNumber) } + // 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx + const sendFlow = async (messageToSend, numberOrId) => { + const queue = [] + for (const ctxMessage of messageToSend) { + const delayMs = ctxMessage?.options?.delay || 0 + if (delayMs) await delay(delayMs) + QueuePrincipal.enqueue(() => + Promise.all([ + this.sendProviderAndSave(numberOrId, ctxMessage), + resolveCbEveryCtx(ctxMessage), + ]) + ) + } + return Promise.all(queue) + } + // 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje - const fallBack = () => { + const fallBack = async () => { fallBackFlag = true - msgToSend = this.flowClass.find(refToContinue?.keyword, true) || [] - this.sendFlow(msgToSend, from) + await this.sendProviderAndSave(from, refToContinue) + QueuePrincipal.queue = [] return refToContinue } // 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes // para evitar bloque de whatsapp - const flowDynamic = (listMsg = [], optListMsg = { limit: 3 }) => { + const flowDynamic = async ( + listMsg = [], + optListMsg = { limit: 5, fallback: false } + ) => { if (!Array.isArray(listMsg)) throw new Error('Esto debe ser un ARRAY') + fallBackFlag = optListMsg.fallback const parseListMsg = listMsg .map(({ body }, index) => toCtx({ @@ -108,26 +131,38 @@ class CoreClass { }) ) .slice(0, optListMsg.limit) - msgToSend = parseListMsg - this.sendFlow(msgToSend, from) + for (const msg of parseListMsg) { + await this.sendProviderAndSave(from, msg) + } return } + // 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback + const resolveCbEveryCtx = async (ctxMessage) => { + if (prevMsg?.options?.capture) return cbEveryCtx(prevMsg?.ref) + if (!ctxMessage?.options?.capture) + return await cbEveryCtx(ctxMessage?.ref) + } + // 📄 Se encarga de revisar si el contexto del mensaje tiene callback y ejecutarlo - const cbEveryCtx = (inRef) => { - this.flowClass.allCallbacks[inRef](messageCtxInComming, { + const cbEveryCtx = async (inRef) => { + if (!this.flowClass.allCallbacks[inRef]) return Promise.resolve() + return this.flowClass.allCallbacks[inRef](messageCtxInComming, { fallBack, flowDynamic, }) } + if (prevMsg?.ref) resolveCbEveryCtx(prevMsg) + // 📄 [options: callback]: Si se tiene un callback se ejecuta - if (!fallBackFlag) { - if (refToContinue?.options?.capture) cbEveryCtx(refToContinue?.ref) - for (const ite of this.flowClass.find(body)) { - if (!ite?.options?.capture) cbEveryCtx(ite?.ref) - } - } + //TODO AQUI + // if (!fallBackFlag) { + // if (prevMsg?.options?.capture) cbEveryCtx(prevMsg?.ref) + // for (const ite of this.flowClass.find(body)) { + // if (!ite?.options?.capture) cbEveryCtx(ite?.ref) + // } + // } // 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa if (!fallBackFlag && prevMsg?.options?.nested?.length) { @@ -138,11 +173,12 @@ class CoreClass { msgToSend = this.flowClass.find(body, false, flowStandalone) || [] - for (const ite of msgToSend) { - cbEveryCtx(ite?.ref) - } + // //TODO AQUI + // for (const ite of msgToSend) { + // cbEveryCtx(ite?.ref) + // } - this.sendFlow(msgToSend, from) + sendFlow(msgToSend, from) return } @@ -153,13 +189,13 @@ class CoreClass { if (['string', 'boolean'].includes(typeCapture) && valueCapture) { msgToSend = this.flowClass.find(refToContinue?.ref, true) || [] - this.sendFlow(msgToSend, from) + sendFlow(msgToSend, from) return } } msgToSend = this.flowClass.find(body) || [] - this.sendFlow(msgToSend, from) + sendFlow(msgToSend, from) } /** @@ -176,18 +212,6 @@ class CoreClass { ]) } - sendFlow = async (messageToSend, numberOrId) => { - const queue = [] - for (const ctxMessage of messageToSend) { - const delayMs = ctxMessage?.options?.delay || 0 - if (delayMs) await delay(delayMs) - Queue.enqueue(() => - this.sendProviderAndSave(numberOrId, ctxMessage) - ) - } - return Promise.all(queue) - } - /** * @private * @param {*} message diff --git a/packages/bot/package.json b/packages/bot/package.json index fa7dc12..d3f004e 100644 --- a/packages/bot/package.json +++ b/packages/bot/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/bot", - "version": "0.0.41-alpha.0", + "version": "0.0.66-alpha.0", "description": "", "main": "./lib/bundle.bot.cjs", "scripts": { @@ -28,5 +28,9 @@ }, "dependencies": { "dotenv": "^16.0.3" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/bot" } } diff --git a/packages/bot/rollup-bot.config.js b/packages/bot/rollup-bot.config.js index f8ffa2a..36bbb87 100644 --- a/packages/bot/rollup-bot.config.js +++ b/packages/bot/rollup-bot.config.js @@ -10,6 +10,7 @@ module.exports = [ banner: banner['banner.output'].join(''), file: join(__dirname, 'lib', 'bundle.bot.cjs'), format: 'cjs', + sourcemap: true, }, plugins: [commonjs(), nodeResolve()], }, diff --git a/packages/bot/utils/queue.js b/packages/bot/utils/queue.js index 1f610e9..873024a 100644 --- a/packages/bot/utils/queue.js +++ b/packages/bot/utils/queue.js @@ -1,8 +1,8 @@ class Queue { - static queue = [] - static pendingPromise = false + queue = [] + pendingPromise = false - static enqueue(promise) { + enqueue(promise) { return new Promise((resolve, reject) => { this.queue.push({ promise, @@ -13,7 +13,7 @@ class Queue { }) } - static dequeue() { + dequeue() { if (this.workingOnPromise) { return false } diff --git a/packages/cli/check/index.js b/packages/cli/check/index.js index 73d5924..cbd8e08 100644 --- a/packages/cli/check/index.js +++ b/packages/cli/check/index.js @@ -1,38 +1,65 @@ const { red, yellow, green, bgCyan } = require('kleur') +const { exec } = require('node:child_process') const checkNodeVersion = () => { - console.log(bgCyan('🚀 Revisando tu Node.js')) - const version = process.version - const majorVersion = parseInt(version.replace('v', '').split('.').shift()) - if (majorVersion < 16) { - console.error( - red( - `🔴 Se require Node.js 16 o superior. Actualmente esta ejecutando Node.js ${version}` - ) + return new Promise((resolve, reject) => { + console.log(bgCyan('🚀 Revisando tu Node.js')) + const version = process.version + const majorVersion = parseInt( + version.replace('v', '').split('.').shift() ) - process.exit(1) - } - console.log(green(`Node.js compatible ${version}`)) - console.log(``) + if (majorVersion < 16) { + console.error( + red( + `🔴 Se require Node.js 16 o superior. Actualmente esta ejecutando Node.js ${version}` + ) + ) + console.log(``) + reject('ERROR_NODE') + } + console.log(green(`Node.js: ${version} compatible ✅`)) + console.log(``) + resolve() + }) } const checkOs = () => { - console.log(bgCyan('🙂 Revisando tu sistema operativo')) - const os = process.platform - if (!os.includes('win32')) { - const messages = [ - `El sistema operativo actual (${os}) posiblemente requiera`, - `una configuración adicional referente al puppeteer`, - ``, - `Recuerda pasar por el WIKI`, - `🔗 https://github.com/leifermendez/bot-whatsapp/wiki/Instalación`, - ``, - ] + return new Promise((resolve, reject) => { + console.log(bgCyan('🙂 Revisando tu sistema operativo')) + const os = process.platform + if (!os.includes('win32')) { + const messages = [ + `El sistema operativo actual (${os}) posiblemente requiera`, + `una configuración adicional referente al puppeteer`, + ``, + `Recuerda pasar por el WIKI`, + `🔗 https://github.com/leifermendez/bot-whatsapp/wiki/Instalación`, + ``, + ] - console.log(yellow(messages.join(' \n'))) - } - - console.log(``) + console.log(yellow(messages.join(' \n'))) + } + console.log(green(`OS: compatible ✅`)) + console.log(``) + resolve() + }) } -module.exports = { checkNodeVersion, checkOs } +const checkGit = () => { + return new Promise((resolve, reject) => { + console.log(bgCyan('🤓 Revisando GIT')) + exec('git --version', (error) => { + if (error) { + console.error(red(`🔴 Se require instalar GIT`)) + console.log(``) + reject('ERROR_GIT') + } else { + console.log(green(`Git: Compatible ✅`)) + console.log(``) + resolve() + } + }) + }) +} + +module.exports = { checkNodeVersion, checkOs, checkGit } diff --git a/packages/cli/interactive/index.js b/packages/cli/interactive/index.js index a0a4034..b3f063d 100644 --- a/packages/cli/interactive/index.js +++ b/packages/cli/interactive/index.js @@ -1,9 +1,9 @@ const prompts = require('prompts') const { join } = require('path') -const { yellow, red, cyan, bgMagenta } = require('kleur') +const { yellow, red, cyan, bgMagenta, bgRed } = require('kleur') const { existsSync } = require('fs') const { copyBaseApp } = require('../create-app') -const { checkNodeVersion, checkOs } = require('../check') +const { checkNodeVersion, checkOs, checkGit } = require('../check') const bannerDone = () => { console.log(``) @@ -21,6 +21,22 @@ const bannerDone = () => { } const startInteractive = async () => { + try { + console.clear() + await checkNodeVersion() + checkOs() + await checkGit() + console.clear() + await nextSteps() + } catch (e) { + console.error(bgRed(`Ups! 🙄 algo no va bien.`)) + console.error( + bgRed(`Revisa los requerimientos minimos en la documentacion`) + ) + } +} + +const nextSteps = async () => { const questions = [ { type: 'text', @@ -58,9 +74,6 @@ const startInteractive = async () => { }, ] - console.clear() - checkNodeVersion() - checkOs() const onCancel = () => { console.log('¡Proceso cancelado!') return true diff --git a/packages/cli/package.json b/packages/cli/package.json index 5a86b89..60361be 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/cli", - "version": "0.0.48-alpha.0", + "version": "0.0.72-alpha.0", "description": "", "main": "index.js", "devDependencies": { @@ -15,5 +15,9 @@ ], "bin": { "bot": "./bin/cli.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/cli" } } diff --git a/packages/contexts/package.json b/packages/contexts/package.json index 29c2dcd..c186a5f 100644 --- a/packages/contexts/package.json +++ b/packages/contexts/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/contexts", - "version": "0.0.1", + "version": "0.0.16-alpha.0", "description": "", "main": "./lib/bundle.contexts.cjs", "files": [ @@ -13,5 +13,9 @@ }, "dependencies": { "@bot-whatsapp/bot": "*" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/contexts" } } diff --git a/packages/contexts/src/dialogflow/dialogflow.class.js b/packages/contexts/src/dialogflow/dialogflow.class.js index ffe50e7..ebd92bc 100644 --- a/packages/contexts/src/dialogflow/dialogflow.class.js +++ b/packages/contexts/src/dialogflow/dialogflow.class.js @@ -97,13 +97,21 @@ class DialogFlowContext extends CoreClass { }) customPayload = { - media: fields?.media?.stringValue, - buttons: mapButtons, + options: { + media: fields?.media?.stringValue, + buttons: mapButtons, + }, } + + const ctxFromDX = { + ...customPayload, + answer: fields?.answer?.stringValue, + } + this.sendFlow([ctxFromDX], from) + return } const ctxFromDX = { - ...customPayload, answer: queryResult?.fulfillmentText, } diff --git a/packages/create-bot-whatsapp/package.json b/packages/create-bot-whatsapp/package.json index c96f366..3b372ca 100644 --- a/packages/create-bot-whatsapp/package.json +++ b/packages/create-bot-whatsapp/package.json @@ -1,6 +1,6 @@ { "name": "create-bot-whatsapp", - "version": "0.0.59-alpha.0", + "version": "0.0.93-alpha.0", "description": "", "main": "./lib/bundle.create-bot-whatsapp.cjs", "files": [ @@ -11,5 +11,9 @@ "bin": "./bin/create.js", "dependencies": { "@bot-whatsapp/cli": "*" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/create-bot-whatsapp" } } diff --git a/packages/database/package.json b/packages/database/package.json index 50a5cee..f69d0c9 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -1,6 +1,6 @@ { "name": "@bot-whatsapp/database", - "version": "0.0.40-alpha.0", + "version": "0.0.64-alpha.0", "description": "Esto es el conector a mysql, pg, mongo", "main": "./lib/mock/index.cjs", "keywords": [], @@ -19,5 +19,9 @@ "./mongo": "./lib/mongo/index.cjs", "./json": "./lib/json/index.cjs", "./mysql": "./lib/mysql/index.cjs" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/database" } } diff --git a/packages/docs/src/components/widgets/Hero.tsx b/packages/docs/src/components/widgets/Hero.tsx index 4700421..0e7cc5e 100644 --- a/packages/docs/src/components/widgets/Hero.tsx +++ b/packages/docs/src/components/widgets/Hero.tsx @@ -47,13 +47,20 @@ export default component$(() => { npm create bot-whatsapp@latest -
+
Ver documentación + + Ver video +
diff --git a/packages/docs/src/routes/docs/flows/index.mdx b/packages/docs/src/routes/docs/flows/index.mdx index 027c793..7a2171c 100644 --- a/packages/docs/src/routes/docs/flows/index.mdx +++ b/packages/docs/src/routes/docs/flows/index.mdx @@ -1,6 +1,6 @@ import Navigation from '../../../components/widgets/Navigation' -# Flow (Flujos) +# Flow Los flujos hace referencia al hecho de construir un flujo de conversion. Esto es un flow podemos observar que estan presente dos metodos importantes **addKeyword** y el **addAnswer**. @@ -23,6 +23,142 @@ const flowPrincipal = addKeyword(['hola', 'alo']) --- +## addKeyword() + +Esta funcion se utliza para iniciar un flujo de conversion.
Recibe un `string` o un `array` +de string `['hola','buenas']`. + +**Opciones** + +- sensitive: Sensible a mayusculas y minusculas por defecto `false` + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flowString = addKeyword('hola') + +const flowArray = addKeyword(['hola', 'alo']) + +const flowSensitive = addKeyword(['hola', 'alo'], { + sensitive: true, +}) +``` + +--- + +## addAnswer() + +Esta funcion se utliza para responder un mensaje despues del `addKeyword()` + +**Opciones** + +- delay: 0 (milisegundos) +- media: url de imagen +- buttons: array `[{body:'Boton1'}, {body:'Boton2'}, {body:'Boton3'}]` +- capture: false (para esperar respuesta) +- child: Objecto tipo flujo o arra de flujos hijos + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flowString = addKeyword('hola').addAnswer( + 'Este mensaje se enviara 1 segundo despues', + { + delay: 1000, + } +) + +const flowString = addKeyword('hola').addAnswer( + 'Este mensaje envia una imagen', + { + media: 'https://i.imgur.com/0HpzsEm.png', + } +) + +const flowString = addKeyword('hola').addAnswer( + 'Este mensaje envia tres botones', + { + buttons: [ + { body: 'Boton 1' }, + { body: 'Boton 2' }, + { body: 'Boton 3' }, + ], + } +) + +const flowString = addKeyword('hola').addAnswer( + 'Este mensaje espera una respueta del usuario', + { + capture: true, + } +) +``` + +--- + +## ctx + +Este argumento se utiliza para obtener el contexto de la conversación + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flowString = addKeyword('hola').addAnswer( + 'Indica cual es tu email', + null, + (ctx) => { + console.log('👉 Informacion del contexto: ', ctx) + } +) +``` + +--- + +## fallBack() + +Esta funcion se utliza para volver a enviar el ultimo mensaje abajo un ejemplo. +En el ejemplo de abajo esperamos que el usuario ingrese un mensaje que contenga `@` sino contiene +se repetira el mensaje `Indica cual es tu email` + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flowString = addKeyword('hola').addAnswer( + 'Indica cual es tu email', + null, + (ctx, { fallBack }) => { + if (!ctx.body.includes('@')) return fallBack() + } +) +``` + +--- + +## flowDynamic() + +Esta funcion se utliza para devolver mensajes dinamicos que pueden venir de una API o Base de datos. +La funcion recibe un array que debe contener la siguiente estrucutura: + +`[{body:'Mensaje}, {body:'Mensaje2}]` + +```js +const { addKeyword } = require('@bot-whatsapp/bot') + +const flowString = addKeyword('hola') + .addAnswer('Indica cual es tu email', null, async (ctx, {flowDynamic}) => { + const mensajesDB = () => { + const categories = db.find(...) + const mapDatos = categories.map((c) => ({body:c.name})) + return mapDatos + } + await flowDynamic(mensajesDB()) + }) + + +``` + +--- + ⚡ Dependiendo del tipo de proveedor que utlices puede que necesites pasar @@ -33,9 +33,21 @@ Los proveedores disponibles hasta el momento son los siguientes: --- +### Twilio: Configuración + +Estamos trabajando en el apartado de la documentación lo más claro posible. Puedes encontrar los [detalles aquí](/docs/providers/twilio) + +--- + +### Meta: Configuración + +Estamos trabajando en el apartado de la documentación lo más claro posible. Puedes encontrar los [detalles aquí](/docs/providers/meta) + +--- + diff --git a/packages/docs/src/routes/docs/providers/meta/index.mdx b/packages/docs/src/routes/docs/providers/meta/index.mdx new file mode 100644 index 0000000..a44476f --- /dev/null +++ b/packages/docs/src/routes/docs/providers/meta/index.mdx @@ -0,0 +1,159 @@ +import Alert from '../../../../components/widgets/Alert' +import Navigation from '../../../../components/widgets/Navigation' + +# Meta + +La Plataforma de WhatsApp Business permite a medianas y grandes empresas comunicarse con sus clientes a gran escala. +Puedes iniciar conversaciones con clientes en apenas unos minutos, enviarles notificaciones de atención al cliente o actualizaciones de compras, ofrecerles un nivel de servicio personalizado y +prestarles ayuda a través del canal que ellos prefieran. + +### Requerimientos + +- Registrar una cuenta de [facebook developers](https://developers.facebook.com/apps) + +--- + +### Requerimientos + +Debes crear una aplicación nueva. Para ello haz clic en el botón **Crear aplicación** + +![](https://i.imgur.com/DKgjwj9.png) + +--- + +En esta pantalla debes de seleccionar **Empresa o Business** + +![](https://i.imgur.com/tapmpMk.png) + +--- + +En el siguiente paso debes escribir un nombre al tu aplicación también colocar un email de contacto y seleccionar la aplicación de Test Business + +![](https://i.imgur.com/cfHLJTJ.png) + +--- + +Ahora dirígete a la sección de Ajustes de WhatsApp. + +![](https://i.imgur.com/37gMMM5.png) + +--- + +Está la parte donde encontraras el token acceso y también puedes ver el número **desde donde** se envía los mensajes de WhatsApp +y **a donde** se va a enviar. +Como estás en la versión de prueba, deberás dar de alta los números a los que quieres enviar. + +![](https://i.imgur.com/bkSAZn2.png) + +--- + +En esta misma página puedes encontrar el apartado de **Webhook** que pronto necesitaremos usar + +![](https://i.imgur.com/L3PRcj7.png) + +--- + +En el **archivo principal** del bot donde estás implementando la función del adaptador de meta vas a colocar los siguientes datos: + +- **numberId:** Lo puedes encontrar en la pagina anterior +- **jwtToken:** Lo puedes encontrar en la pagina anterior +- **verifyToken:** Puedes escribir lo que quieras es como una palabra clave + + + En el ejemplo de abajo puedes ver como una sugerencia de como puede ser + utilizando variables de entorno + + +```js +const main = async () => { + const adapterDB = new MockAdapter() + const adapterFlow = createFlow([flowPrincipal]) + + const adapterProvider = createProvider(MetaProvider, { + jwtToken: process.env.JWTOKEN, //EAARBW3ZBGU0UBAACDjtQIzI8JuEa............. + numberId: process.env.NUMBER_ID, //103975305758520 + verifyToken: process.env.VERIFY_TOKEN, //LO_QUE_SEA + }) + + createBot({ + flow: adapterFlow, + provider: adapterProvider, + database: adapterDB, + }) +} + +main() +``` + +--- + +Luego de ejecutar el bot encontraras un mensaje en la consola similar al siguiente. +Donde podrás encontrar la URL para tu **webhook** + +```shell +$ npm start + +> bot-whatsapp-base-meta-memory@1.0.0 start +> node app.js + + +[meta]: Agregar esta url "WHEN A MESSAGE COMES IN" +[meta]: POST http://localhost:3000/webhook +[meta]: Más información en la documentacion +``` + +--- + +## ¿Ahora que hago? + +Podrás observar que el bot inicia un servicio HTTP (endpoint) que debe estar en un servidor en linea para que puedas conectarlo con Meta. + +--- + +### Opción 1: + +Puedes hacer pruebas en local atrevés de un servidor proxy tunnel.  +Descarga **[ngork](https://ngrok.com/download)** es una herramienta gratuita que nos ayudara con esto. + +![](https://i.imgur.com/TjjBtRh.png) + +--- + +Esto genera una URL en línea que podemos usar en la parte de **WebHook** de Meta + +![](https://i.imgur.com/NXHMDsf.png) + +--- + +![](https://i.imgur.com/tpov3D1.png) + +--- + +![](https://i.imgur.com/haRGylR.png) + +--- + +![](https://i.imgur.com/cMaIzeC.png) + +--- + +### Opción 2: + +Si ya tienes desplegado tu bot en un servidor tienes que obtener la IP publica o subdominio que te proporcionaron. **Ejemplo** si estas usando +[Railway](https://railway.app/) puedes ir a la seccion de ajustes y generar un subdominio. Ya tendriamos el **WebHook** +`https://base-twilio-memory-production.up.railway.app/twilio-hook` + +![](https://i.imgur.com/Yg2BYqB.png) + +--- + +![](https://i.imgur.com/dIbyEwp.png) + +--- + + diff --git a/packages/docs/src/routes/docs/providers/twilio/index.mdx b/packages/docs/src/routes/docs/providers/twilio/index.mdx new file mode 100644 index 0000000..5548ad5 --- /dev/null +++ b/packages/docs/src/routes/docs/providers/twilio/index.mdx @@ -0,0 +1,152 @@ +import Alert from '../../../../components/widgets/Alert' +import Navigation from '../../../../components/widgets/Navigation' + +# Twilio + +Twilio es una plataforma de desarrollo que permite a los desarrolladores construir aplicaciones de comunicación en la nube y sistemas web. Las API de comunicaciones de Twilio permiten a las empresas proporcionar la experiencia de comunicación adecuada para sus clientes dentro de la web y las aplicaciones móviles. Al usar las API de Twilio, los desarrolladores pueden agregar rápidamente esta funcionalidad a una aplicación, como mensajes de voz, videollamadas, mensajes de texto y más. + + + Twilio te proporciona una cuenta **Sandbox** para que puedas probar + gratuitamente el servicio + + +### Requerimientos + +- Registrar una cuenta de [twilio](https://www.twilio.com/try-twilio) + +--- + +### Requerimientos + +Debemos aceptar los términos y condiciones y luego activar la cuenta sandbox + +![](https://i.imgur.com/53RyhZD.png) + +--- + +Observamos que ahora tenemos un número de WhatsApp y una frase. El número proporcionado es un **número de pruebas** que te ofrece Twilio, luego que actives un plan de pago puedes comprar un número para tu uso.  +Guarda ese número como un contacto de WhatsApp en tu móvil y después envíale el mensaje que te asignan. En el ejemplo de la pantalla sale **join score-state** + +![](https://i.imgur.com/Eb69grk.png) + +--- + +Luego Twilio te responde con un mensaje confirmando la verificación de la conexión. **Este paso solo es necesario cuando estás en modo Sandbox.** + +![](https://i.imgur.com/cTWNxBF.png) + +--- + +Ahora dirígete a la sección de Ajustes de WhatsApp ubicada en la consola de Twilio. + +![](https://i.imgur.com/UQG8LkW.png) + +--- + +En esta sección puedes configurar los **Webhook** que conectaran con el chatbot. + +**¿No sabes cuál es tu link?** continúa leyendo esta guía más adelante entenderás + +![](https://i.imgur.com/WovZGPm.png) + +--- + +También necesitarás el **Account SID y Auth Token** estos datos los consigues [console.twilio.com](https://console.twilio.com). + +**¿Que hago con estos datos?** guardalos o tenlos ubicados porque los necesitaremos en las siguientes pantallas + +![](https://i.imgur.com/RxlxEEm.png) + +--- + +En el **archivo principal** del bot donde estás implementando la función del adaptador de twilio vas a colocar los siguientes datos: + +- **ACC_SID:** Lo encontraras en console.twilio puedes ver la pantalla anterior +- **ACC_TOKEN:** Lo encontraras en console.twilio puedes ver la pantalla anterior +- **ACC_VENDOR:** Es el numero de whatsapp (si ya tienes el plan de pago de Twilio usa el numero que compraste), si aun estas en modo + sandbox utliza el numero proporcionado en el paso numero 2 + + + En el ejemplo de abajo puedes ver como una sugerencia de como puede ser + utilizando variables de entorno + + +```js +const main = async () => { + const adapterDB = new MockAdapter() + const adapterFlow = createFlow([flowPrincipal]) + + const adapterProvider = createProvider(TwilioProvider, { + accountSid: process.env.ACC_SID, //AC4695aa720b4d700a*************** + authToken: process.env.ACC_TOKEN, //3f6fae09f7a1c3534*************** + vendorNumber: process.env.ACC_VENDOR, //+14155238886 + }) + + createBot({ + flow: adapterFlow, + provider: adapterProvider, + database: adapterDB, + }) +} +``` + +--- + +Luego de ejecutar el bot encontraras un mensaje en la consola similar al siguiente. +Donde podrás encontrar la URL para tu **webhook** + +```shell +$ npm start + +> bot-whatsapp-base-twilio-memory@1.0.0 start +> node app.js + + +[Twilio]: Agregar esta url "WHEN A MESSAGE COMES IN" +[Twilio]: POST http://localhost:3000/twilio-hook +[Twilio]: Más información en la documentacion +``` + +--- + +## ¿Ahora que hago? + +Podrás observar que el bot inicia un servicio HTTP (endpoint) que debe estar en un servidor en linea para que puedas conectarlo con Twilio. + +--- + +### Opción 1: + +Puedes hacer pruebas en local atrevés de un servidor proxy tunnel.  +Descarga **[ngork](https://ngrok.com/download)** es una herramienta gratuita que nos ayudara con esto. + +![](https://i.imgur.com/TjjBtRh.png) + +--- + +Esto genera una URL en línea que podemos usar en la parte de **WebHook** de Twilio + +![](https://i.imgur.com/S9zXROt.png) + +--- + +### Opción 2: + +Si ya tienes desplegado tu bot en un servidor tienes que obtener la IP publica o subdominio que te proporcionaron. **Ejemplo** si estas usando +[Railway](https://railway.app/) puedes ir a la seccion de ajustes y generar un subdominio. Ya tendriamos el **WebHook** +`https://base-twilio-memory-production.up.railway.app/twilio-hook` + +![](https://i.imgur.com/Yg2BYqB.png) + +--- + +![](https://i.imgur.com/dpv6RTR.png) + +--- + + diff --git a/packages/docs/src/routes/docs/requirements/index.mdx b/packages/docs/src/routes/docs/requirements/index.mdx index 03718d2..8f1ef96 100644 --- a/packages/docs/src/routes/docs/requirements/index.mdx +++ b/packages/docs/src/routes/docs/requirements/index.mdx @@ -4,14 +4,8 @@ import Navigation from '../../../components/widgets/Navigation' A continuación se describen los puntos técnicos que debes de tener en cuenta antes de trabajar con esta herramienta -- Node v16 o superior **[descargar node](https://nodejs.org/es/download/)** - ---- - -## ¿Como instalar Node? - -- **Windows**: [Ver video](https://youtu.be/xRXHQlqA3Ak?t=376). Necesita ayuda para instalar Node en Windows. A continuación te comparto un video en el minuto exacto donde explico como instalar. -- **Ubuntu**: Te comparto un recurso de **[Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-es)** donde explica como instalar node en Ubuntu. +- Node v16 o superior - **[descargar node](https://nodejs.org/es/download/)** +- Git - **[descargar Git](https://git-scm.com/download/win)** --- @@ -26,6 +20,34 @@ v18.12.1 --- +## ¿Como instalar Node? + +- **Windows**: [Ver video](https://youtu.be/xRXHQlqA3Ak?t=376). Si necesitas ayuda para instalar Node en Windows. A continuación te comparto un video en el minuto exacto donde explico como instalar. +- **Ubuntu**: Te comparto un recurso de **[Digital Ocean](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-es)** donde explica como instalar node en Ubuntu. + +--- + +## ¿Como saber que tengo Git? + +Solo debes ejecutar el siguiente comando y esperar que te mande la versión que tienes instalada, si te manda un error de comando no reconocido es que no lo tienes instalado. + +```shell +$ git -v +git +``` + +--- + +## ¿Como instalar Git? + +- Solo es necesario instalar Git si estás usando **Windows**, ya que Mac y Linux lo traen preinstalado. +- Lo puedes descargar desde esta **[liga](https://git-scm.com/download/win)** . +- Descarga la versión necesaria para tu sistema operativo (32-bit o 64-bit). +- Una vez terminada la descarga, ejecuta el archivo descargado y dale "Siguiente" en todas las pantallas. +- Haz clic en el botón de "Finalizar". + +--- + Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build. + +## Preview + +The preview command will create a production build of the client modules, a production build of `src/entry.preview.tsx`, and run a local server. The preview server is only for convenience to locally preview a production build, and it should not be used as a production server. + +```shell +npm run preview # or `yarn preview` +``` + +## Production + +The production build will generate client and server modules by running both client and server build commands. Additionally, the build command will use Typescript to run a type check on the source code. + +```shell +npm run build # or `yarn build` +``` + +## Static Site Generator (Node.js) + +``` +npm run build.server +``` diff --git a/packages/portal/adaptors/static/vite.config.ts b/packages/portal/adaptors/static/vite.config.ts new file mode 100644 index 0000000..dba968a --- /dev/null +++ b/packages/portal/adaptors/static/vite.config.ts @@ -0,0 +1,19 @@ +import { staticAdaptor } from '@builder.io/qwik-city/adaptors/static/vite' +import { extendConfig } from '@builder.io/qwik-city/vite' +import baseConfig from '../../vite.config' + +export default extendConfig(baseConfig, () => { + return { + build: { + ssr: true, + rollupOptions: { + input: ['@qwik-city-plan'], + }, + }, + plugins: [ + staticAdaptor({ + origin: 'https://bot-whatsapp.netlify.app', + }), + ], + } +}) diff --git a/packages/portal/package.json b/packages/portal/package.json new file mode 100644 index 0000000..c26ab32 --- /dev/null +++ b/packages/portal/package.json @@ -0,0 +1,52 @@ +{ + "name": "@bot-whatsapp/portal", + "version": "0.0.22-alpha.0", + "description": "Portal WEB para escanear QR", + "main": "./lib/portal.http.cjs", + "scripts": { + "build": "qwik build", + "build.client": "vite build", + "build.preview": "vite build --ssr src/entry.preview.tsx", + "build.server": "vite build -c adaptors/static/vite.config.ts", + "build.types": "tsc --incremental --noEmit", + "deploy": "echo 'Run \"npm run qwik add\" to install a server adaptor'", + "dev": "vite --mode ssr", + "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", + "fmt": "prettier --write .", + "fmt.check": "prettier --check .", + "lint": "eslint \"src/**/*.ts*\"", + "preview": "qwik build preview && vite preview --open", + "start": "vite --open --mode ssr", + "qwik": "qwik" + }, + "files": [ + "./dist/*", + "./lib/portal.http.cjs" + ], + "devDependencies": { + "@builder.io/qwik": "0.16.2", + "@builder.io/qwik-city": "0.0.128", + "@types/eslint": "8.4.10", + "@types/node": "^18.11.18", + "@types/node-fetch": "latest", + "@typescript-eslint/eslint-plugin": "5.48.0", + "@typescript-eslint/parser": "5.48.0", + "eslint": "8.31.0", + "eslint-plugin-qwik": "0.16.2", + "node-fetch": "3.3.0", + "prettier": "2.8.1", + "typescript": "4.9.4", + "undici": "5.14.0", + "vite": "4.0.3", + "vite-tsconfig-paths": "3.5.0" + }, + "dependencies": { + "kleur": "^4.1.5", + "polka": "^0.5.2", + "serve-static": "^1.13.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/codigoencasa/bot-whatsapp/tree/main/packages/portal" + } +} diff --git a/packages/portal/portal.http.js b/packages/portal/portal.http.js new file mode 100644 index 0000000..3066c12 --- /dev/null +++ b/packages/portal/portal.http.js @@ -0,0 +1,67 @@ +const { join } = require('path') +const { createReadStream, existsSync } = require('fs') +const { bgYellow, cyan, yellow } = require('kleur') +const polka = require('polka') + +const HTTP_PORT = process.env.PORT || 3000 +const QR_FILE = process.env.QR_FILE ?? 'bot' +const PUBLIC_URL = + process.env.PUBLIC_URL ?? + process.env.RAILWAY_STATIC_URL ?? + 'http://localhost' + +const dir = [join(__dirname, 'dist'), join(__dirname, '..', 'dist')].find((i) => + existsSync(i) +) +const serve = require('serve-static')(dir) + +/** + * Iniciamos Portal WEB para escanear QR + * @param {port:3000, publicSite:'http://mistio.com', qrFile:'qr.png', dir:__dirname} + */ +const start = (args) => { + const injectArgs = { + port: HTTP_PORT, + publicSite: PUBLIC_URL, + name: QR_FILE, + ...args, + } + const { port, publicSite, name } = injectArgs + + const banner = () => { + console.log(``) + console.log(bgYellow(`🚩 ESCANEAR QR 🚩`)) + console.log(cyan(`Existen varias maneras de escanear el QR code`)) + console.log( + cyan(`- Tambien puedes visitar `), + yellow(`${publicSite}:${port}`) + ) + console.log( + cyan(`- Se ha creado un archivo que finaliza `), + yellow('qr.png') + ) + console.log(``) + } + + polka() + .use(serve) + .get('qr.png', (_, res) => { + const qrSource = [ + join(process.cwd(), `${name}.qr.png`), + join(__dirname, '..', `${name}.qr.png`), + join(__dirname, `${name}.qr.png`), + ].find((i) => existsSync(i)) + + const qrMark = [ + join(__dirname, 'dist', 'water-mark.png'), + join(__dirname, '..', 'dist', 'water-mark.png'), + ].find((i) => existsSync(i)) + const fileStream = createReadStream(qrSource ?? qrMark) + + res.writeHead(200, { 'Content-Type': 'image/png' }) + fileStream.pipe(res) + }) + .listen(port, () => banner()) +} + +module.exports = start diff --git a/packages/portal/public/favicon.svg b/packages/portal/public/favicon.svg new file mode 100644 index 0000000..0ded7c1 --- /dev/null +++ b/packages/portal/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/portal/public/manifest.json b/packages/portal/public/manifest.json new file mode 100644 index 0000000..44825fa --- /dev/null +++ b/packages/portal/public/manifest.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/web-manifest-combined.json", + "name": "qwik-project-name", + "short_name": "Welcome to Qwik", + "start_url": ".", + "display": "standalone", + "background_color": "#fff", + "description": "A Qwik project app." +} diff --git a/packages/portal/public/robots.txt b/packages/portal/public/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/packages/portal/public/water-mark.png b/packages/portal/public/water-mark.png new file mode 100644 index 0000000..e44ada3 Binary files /dev/null and b/packages/portal/public/water-mark.png differ diff --git a/packages/portal/rollup-portal.config.js b/packages/portal/rollup-portal.config.js new file mode 100644 index 0000000..ee955ff --- /dev/null +++ b/packages/portal/rollup-portal.config.js @@ -0,0 +1,13 @@ +const banner = require('../../config/banner.rollup.json') +const { join } = require('path') +const commonjs = require('@rollup/plugin-commonjs') + +module.exports = { + input: join(__dirname, 'portal.http.js'), + output: { + banner: banner['banner.output'].join(''), + file: join(__dirname, 'lib', 'portal.http.cjs'), + format: 'cjs', + }, + plugins: [commonjs()], +} diff --git a/packages/portal/src/components/header/header.css b/packages/portal/src/components/header/header.css new file mode 100644 index 0000000..b88f3da --- /dev/null +++ b/packages/portal/src/components/header/header.css @@ -0,0 +1,36 @@ +header { + display: flex; + background: white; +} + +header .logo a { + display: inline-block; + padding: 10px 10px 7px 20px; + text-decoration: none; +} + +header ul { + margin: 0; + padding: 3px 10px 0 0; + list-style: none; + flex: 1; + text-align: right; +} + +header li { + display: inline-block; + margin: 0; + padding: 0; +} + +header li a { + display: inline-block; + padding: 15px 10px; + text-decoration: none; + color: #1a1a1a; + font-weight: 500; +} + +header li a:hover { + text-decoration: underline; +} diff --git a/packages/portal/src/components/header/header.tsx b/packages/portal/src/components/header/header.tsx new file mode 100644 index 0000000..f1c7fa7 --- /dev/null +++ b/packages/portal/src/components/header/header.tsx @@ -0,0 +1,47 @@ +import { component$, useStylesScoped$ } from '@builder.io/qwik' +import { BotLogo } from '../icons/bot' +import styles from './header.css?inline' + +export default component$(() => { + useStylesScoped$(styles) + + return ( +
+ + +
+ ) +}) diff --git a/packages/portal/src/components/icons/bot.css b/packages/portal/src/components/icons/bot.css new file mode 100644 index 0000000..481f167 --- /dev/null +++ b/packages/portal/src/components/icons/bot.css @@ -0,0 +1,12 @@ +.logo { + display: flex; + gap: 0.5rem; + align-items: center; + align-content: center; + color: #1a1a1a; +} + +.logo h1 { + font-size: 1.5rem; + margin: 0; +} diff --git a/packages/portal/src/components/icons/bot.tsx b/packages/portal/src/components/icons/bot.tsx new file mode 100644 index 0000000..3c69ef7 --- /dev/null +++ b/packages/portal/src/components/icons/bot.tsx @@ -0,0 +1,18 @@ +import { component$, useStylesScoped$ } from '@builder.io/qwik' + +import styles from './bot.css?inline' + +export const BotLogo = component$(() => { + useStylesScoped$(styles) + return ( +
+ +

Chatbot

+
+ ) +}) diff --git a/packages/portal/src/components/icons/qwik.tsx b/packages/portal/src/components/icons/qwik.tsx new file mode 100644 index 0000000..3bd8d91 --- /dev/null +++ b/packages/portal/src/components/icons/qwik.tsx @@ -0,0 +1,38 @@ +export const QwikLogo = () => ( + + + + + + + + + +) diff --git a/packages/portal/src/components/qr/qr.css b/packages/portal/src/components/qr/qr.css new file mode 100644 index 0000000..37d8779 --- /dev/null +++ b/packages/portal/src/components/qr/qr.css @@ -0,0 +1,12 @@ +div img { + display: block; + background-color: #f0f0f0; + width: 350px; + height: 350px; + object-fit: contain; + border-radius: 10px; +} +div { + display: flex; + justify-content: center; +} diff --git a/packages/portal/src/components/qr/qr.tsx b/packages/portal/src/components/qr/qr.tsx new file mode 100644 index 0000000..52ebe01 --- /dev/null +++ b/packages/portal/src/components/qr/qr.tsx @@ -0,0 +1,31 @@ +import { + component$, + useClientEffect$, + useStore, + useStylesScoped$, +} from '@builder.io/qwik' +import style from './qr.css?inline' + +export const QR = component$(() => { + useStylesScoped$(style) + const state = useStore({ + count: 0, + }) + + useClientEffect$(() => { + setInterval(() => { + state.count++ + }, 800) + }) + + return ( +
+ QR +
+ ) +}) diff --git a/packages/portal/src/components/router-head/router-head.tsx b/packages/portal/src/components/router-head/router-head.tsx new file mode 100644 index 0000000..c0811e4 --- /dev/null +++ b/packages/portal/src/components/router-head/router-head.tsx @@ -0,0 +1,32 @@ +import { component$ } from '@builder.io/qwik' +import { useDocumentHead, useLocation } from '@builder.io/qwik-city' + +export const RouterHead = component$(() => { + const head = useDocumentHead() + const loc = useLocation() + + return ( + <> + {head.title} + + + + + + {head.meta.map((m) => ( + + ))} + + {head.links.map((l) => ( + + ))} + + {head.styles.map((s) => ( +