mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2026-03-21 20:18:40 -06:00
Merge branch 'develop' into fix/meta-cloud-api-chatbot
This commit is contained in:
+4
-1
@@ -12,9 +12,12 @@ WORKDIR /evolution
|
||||
COPY ./package*.json ./
|
||||
COPY ./tsconfig.json ./
|
||||
COPY ./tsup.config.ts ./
|
||||
COPY ./patches ./patches
|
||||
|
||||
RUN npm ci --silent
|
||||
|
||||
RUN npx patch-package
|
||||
|
||||
COPY ./src ./src
|
||||
COPY ./public ./public
|
||||
COPY ./prisma ./prisma
|
||||
@@ -28,7 +31,7 @@ RUN chmod +x ./Docker/scripts/* && dos2unix ./Docker/scripts/*
|
||||
|
||||
RUN ./Docker/scripts/generate_database.sh
|
||||
|
||||
RUN npm run build
|
||||
RUN NODE_OPTIONS="--max-old-space-size=2048" npm run build
|
||||
|
||||
FROM node:24-alpine AS final
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ SQS_ACCESS_KEY_ID=
|
||||
SQS_SECRET_ACCESS_KEY=
|
||||
SQS_ACCOUNT_ID=
|
||||
SQS_REGION=
|
||||
SQS_BASE_URL=
|
||||
SQS_MAX_PAYLOAD_SIZE=1048576
|
||||
|
||||
# ===========================================
|
||||
|
||||
Generated
+289
@@ -94,6 +94,7 @@
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.1.6",
|
||||
"patch-package": "^8.0.1",
|
||||
"prettier": "^3.4.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.20.5",
|
||||
@@ -2907,6 +2908,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
|
||||
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
@@ -2928,6 +2930,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.2.0.tgz",
|
||||
"integrity": "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
@@ -2940,6 +2943,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz",
|
||||
"integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
@@ -2955,6 +2959,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.204.0.tgz",
|
||||
"integrity": "sha512-vV5+WSxktzoMP8JoYWKeopChy6G3HKk4UQ2hESCRDUUTZqQ3+nM3u8noVG0LmNfRWwcFBnbZ71GKC7vaYYdJ1g==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/api-logs": "0.204.0",
|
||||
"import-in-the-middle": "^1.8.1",
|
||||
@@ -3362,6 +3367,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz",
|
||||
"integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.2.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
@@ -3378,6 +3384,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz",
|
||||
"integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.2.0",
|
||||
"@opentelemetry/resources": "2.2.0",
|
||||
@@ -3395,6 +3402,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.38.0.tgz",
|
||||
"integrity": "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
@@ -3643,6 +3651,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz",
|
||||
"integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.2",
|
||||
"generic-pool": "3.9.0",
|
||||
@@ -4933,6 +4942,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -5108,6 +5118,7 @@
|
||||
"integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.47.0",
|
||||
"@typescript-eslint/types": "8.47.0",
|
||||
@@ -5365,6 +5376,13 @@
|
||||
"url": "https://github.com/sponsors/eshaz"
|
||||
}
|
||||
},
|
||||
"node_modules/@yarnpkg/lockfile": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
|
||||
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@zxing/text-encoding": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
|
||||
@@ -5411,6 +5429,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -5758,6 +5777,7 @@
|
||||
"resolved": "https://registry.npmjs.org/audio-decode/-/audio-decode-2.2.3.tgz",
|
||||
"integrity": "sha512-Z0lHvMayR/Pad9+O9ddzaBJE0DrhZkQlStrC1RwcAHF3AhQAsdwKHeLGK8fYKyp2DDU6xHxzGb4CLMui12yVrg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@wasm-audio-decoders/flac": "^0.2.4",
|
||||
"@wasm-audio-decoders/ogg-vorbis": "^0.1.15",
|
||||
@@ -6295,6 +6315,22 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/ci-info": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
|
||||
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/sibiraj-s"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/citty": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
|
||||
@@ -6746,6 +6782,7 @@
|
||||
"integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"env-paths": "^2.2.1",
|
||||
"import-fresh": "^3.3.0",
|
||||
@@ -7636,6 +7673,7 @@
|
||||
"integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@@ -7706,6 +7744,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -7762,6 +7801,7 @@
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -8368,6 +8408,7 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -8736,6 +8777,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/find-yarn-workspace-root": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz",
|
||||
"integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"micromatch": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/findup-sync": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz",
|
||||
@@ -9994,6 +10045,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-docker": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"is-docker": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
@@ -10337,6 +10404,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
@@ -10355,6 +10435,7 @@
|
||||
"resolved": "https://registry.npmjs.org/jimp/-/jimp-1.6.0.tgz",
|
||||
"integrity": "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/diff": "1.6.0",
|
||||
@@ -10459,6 +10540,26 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-stable-stringify": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz",
|
||||
"integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"call-bound": "^1.0.4",
|
||||
"isarray": "^2.0.5",
|
||||
"jsonify": "^0.0.1",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/json-stable-stringify-without-jsonify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||
@@ -10492,6 +10593,16 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonify": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
|
||||
"integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
|
||||
"dev": true,
|
||||
"license": "Public Domain",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonparse": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
|
||||
@@ -10585,10 +10696,21 @@
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.4.tgz",
|
||||
"integrity": "sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@keyv/serialize": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/klaw-sync": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
|
||||
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
@@ -10680,6 +10802,7 @@
|
||||
"resolved": "https://registry.npmjs.org/link-preview-js/-/link-preview-js-3.2.0.tgz",
|
||||
"integrity": "sha512-FvrLltjOPGbTzt+RugbzM7g8XuUNLPO2U/INSLczrYdAA32E7nZVUrVL1gr61DGOArGJA2QkPGMEvNMLLsXREA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cheerio": "1.0.0-rc.11",
|
||||
"url": "0.11.0"
|
||||
@@ -12126,6 +12249,23 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/open": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
|
||||
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0",
|
||||
"is-wsl": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openai": {
|
||||
"version": "4.104.0",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
|
||||
@@ -12528,6 +12668,137 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz",
|
||||
"integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"chalk": "^4.1.2",
|
||||
"ci-info": "^3.7.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"find-yarn-workspace-root": "^2.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"json-stable-stringify": "^1.0.2",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"minimist": "^1.2.6",
|
||||
"open": "^7.4.2",
|
||||
"semver": "^7.5.3",
|
||||
"slash": "^2.0.0",
|
||||
"tmp": "^0.2.4",
|
||||
"yaml": "^2.2.2"
|
||||
},
|
||||
"bin": {
|
||||
"patch-package": "index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">5"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/patch-package/node_modules/fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/patch-package/node_modules/tmp": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
|
||||
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
|
||||
@@ -12600,6 +12871,7 @@
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.9.1",
|
||||
"pg-pool": "^3.10.1",
|
||||
@@ -12909,6 +13181,7 @@
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -12938,6 +13211,7 @@
|
||||
"integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@prisma/config": "6.19.0",
|
||||
"@prisma/engines": "6.19.0"
|
||||
@@ -14029,6 +14303,7 @@
|
||||
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@img/colour": "^1.0.0",
|
||||
"detect-libc": "^2.1.2",
|
||||
@@ -14194,6 +14469,16 @@
|
||||
"url": "https://github.com/sponsors/eshaz"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
||||
@@ -14871,6 +15156,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -15059,6 +15345,7 @@
|
||||
"integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "~0.25.0",
|
||||
"get-tsconfig": "^4.7.5"
|
||||
@@ -15707,6 +15994,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -16222,6 +16510,7 @@
|
||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
|
||||
+3
-1
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "tsc --noEmit && tsup",
|
||||
"start": "tsx ./src/main.ts",
|
||||
"start:prod": "node dist/main",
|
||||
"start:prod": "node --network-family-autoselection-attempt-timeout=1000 dist/main",
|
||||
"dev:server": "tsx watch ./src/main.ts",
|
||||
"test": "tsx watch ./test/all.test.ts",
|
||||
"lint": "eslint --fix --ext .ts src",
|
||||
@@ -20,6 +20,7 @@
|
||||
"db:studio": "node runWithProvider.js \"npx prisma studio --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"",
|
||||
"db:migrate:dev": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate dev --schema ./prisma/DATABASE_PROVIDER-schema.prisma && cp -r ./prisma/migrations/* ./prisma/DATABASE_PROVIDER-migrations\"",
|
||||
"db:migrate:dev:win": "node runWithProvider.js \"xcopy /E /I prisma\\DATABASE_PROVIDER-migrations prisma\\migrations && npx prisma migrate dev --schema prisma\\DATABASE_PROVIDER-schema.prisma\"",
|
||||
"postinstall": "patch-package",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"repository": {
|
||||
@@ -150,6 +151,7 @@
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.1.6",
|
||||
"patch-package": "^8.0.1",
|
||||
"prettier": "^3.4.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.20.5",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/baileys/lib/Utils/messages.js b/node_modules/baileys/lib/Utils/messages.js
|
||||
index 17b05b8..782efb4 100644
|
||||
--- a/node_modules/baileys/lib/Utils/messages.js
|
||||
+++ b/node_modules/baileys/lib/Utils/messages.js
|
||||
@@ -132,7 +132,7 @@ export const prepareWAMessageMedia = async (message, options) => {
|
||||
}
|
||||
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
||||
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
||||
- const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
||||
+ const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
||||
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
||||
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
||||
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
|
||||
@@ -131,8 +131,7 @@ ALTER TABLE `IntegrationSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRE
|
||||
MODIFY `updatedAt` TIMESTAMP NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `IsOnWhatsapp` DROP COLUMN `lid`,
|
||||
MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ALTER TABLE `IsOnWhatsapp` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
MODIFY `updatedAt` TIMESTAMP NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `Instance` MODIFY `token` VARCHAR(500);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Re-add lid column that was incorrectly dropped by previous migration
|
||||
-- This migration ensures backward compatibility for existing installations
|
||||
|
||||
-- Check if column exists before adding
|
||||
SET @dbname = DATABASE();
|
||||
SET @tablename = 'IsOnWhatsapp';
|
||||
SET @columnname = 'lid';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE `', @tablename, '` ADD COLUMN `', @columnname, '` VARCHAR(100);')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
@@ -70,7 +70,7 @@ model Instance {
|
||||
integration String? @db.VarChar(100)
|
||||
number String? @db.VarChar(100)
|
||||
businessId String? @db.VarChar(100)
|
||||
token String? @db.VarChar(255)
|
||||
token String? @db.VarChar(500)
|
||||
clientName String? @db.VarChar(100)
|
||||
disconnectionReasonCode Int? @db.Int
|
||||
disconnectionObject Json? @db.Json
|
||||
@@ -655,6 +655,7 @@ model IsOnWhatsapp {
|
||||
id String @id @default(cuid())
|
||||
remoteJid String @unique @db.VarChar(100)
|
||||
jidOptions String
|
||||
lid String? @db.VarChar(100)
|
||||
createdAt DateTime @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp
|
||||
updatedAt DateTime @updatedAt @db.Timestamp
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Instance" ALTER COLUMN "token" TYPE VARCHAR(500);
|
||||
|
||||
@@ -70,7 +70,7 @@ model Instance {
|
||||
integration String? @db.VarChar(100)
|
||||
number String? @db.VarChar(100)
|
||||
businessId String? @db.VarChar(100)
|
||||
token String? @db.VarChar(255)
|
||||
token String? @db.VarChar(500)
|
||||
clientName String? @db.VarChar(100)
|
||||
disconnectionReasonCode Int? @db.Integer
|
||||
disconnectionObject Json? @db.JsonB
|
||||
|
||||
@@ -71,7 +71,7 @@ model Instance {
|
||||
integration String? @db.VarChar(100)
|
||||
number String? @db.VarChar(100)
|
||||
businessId String? @db.VarChar(100)
|
||||
token String? @db.VarChar(255)
|
||||
token String? @db.VarChar(500)
|
||||
clientName String? @db.VarChar(100)
|
||||
disconnectionReasonCode Int? @db.Integer
|
||||
disconnectionObject Json? @db.JsonB
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ArchiveChatDto,
|
||||
BlockUserDto,
|
||||
DecryptPollVoteDto,
|
||||
DeleteMessage,
|
||||
getBase64FromMediaMessageDto,
|
||||
MarkChatUnreadDto,
|
||||
@@ -113,4 +114,16 @@ export class ChatController {
|
||||
public async blockUser({ instanceName }: InstanceDto, data: BlockUserDto) {
|
||||
return await this.waMonitor.waInstances[instanceName].blockUser(data);
|
||||
}
|
||||
|
||||
public async decryptPollVote({ instanceName }: InstanceDto, data: DecryptPollVoteDto) {
|
||||
const pollCreationMessageKey = {
|
||||
id: data.message.key.id,
|
||||
remoteJid: data.remoteJid,
|
||||
};
|
||||
return await this.waMonitor.waInstances[instanceName].baileysDecryptPollVote(pollCreationMessageKey);
|
||||
}
|
||||
|
||||
public async fetchChannels({ instanceName }: InstanceDto, query: Query<Contact>) {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchChannels(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,3 +127,12 @@ export class BlockUserDto {
|
||||
number: string;
|
||||
status: 'block' | 'unblock';
|
||||
}
|
||||
|
||||
export class DecryptPollVoteDto {
|
||||
message: {
|
||||
key: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
remoteJid: string;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export class Options {
|
||||
mentionsEveryOne?: boolean;
|
||||
mentioned?: string[];
|
||||
webhookUrl?: string;
|
||||
messageId?: string;
|
||||
}
|
||||
|
||||
export class MediaMessage {
|
||||
@@ -45,6 +46,7 @@ export class Metadata {
|
||||
mentioned?: string[];
|
||||
encoding?: boolean;
|
||||
notConvertSticker?: boolean;
|
||||
messageId?: string;
|
||||
}
|
||||
|
||||
export class SendTextDto extends Metadata {
|
||||
|
||||
@@ -318,7 +318,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
||||
|
||||
let audioFile;
|
||||
|
||||
const messageId = v4();
|
||||
const messageId = options?.messageId ?? v4();
|
||||
|
||||
let messageRaw: any;
|
||||
|
||||
@@ -548,6 +548,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
||||
linkPreview: data?.linkPreview,
|
||||
mentionsEveryOne: data?.mentionsEveryOne,
|
||||
mentioned: data?.mentioned,
|
||||
messageId: data?.messageId,
|
||||
},
|
||||
null,
|
||||
isIntegration,
|
||||
@@ -613,6 +614,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
||||
linkPreview: data?.linkPreview,
|
||||
mentionsEveryOne: data?.mentionsEveryOne,
|
||||
mentioned: data?.mentioned,
|
||||
messageId: data?.messageId,
|
||||
},
|
||||
file,
|
||||
isIntegration,
|
||||
@@ -711,6 +713,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
||||
linkPreview: data?.linkPreview,
|
||||
mentionsEveryOne: data?.mentionsEveryOne,
|
||||
mentioned: data?.mentioned,
|
||||
messageId: data?.messageId,
|
||||
},
|
||||
file,
|
||||
isIntegration,
|
||||
@@ -736,6 +739,7 @@ export class EvolutionStartupService extends ChannelStartupService {
|
||||
quoted: data?.quoted,
|
||||
mentionsEveryOne: data?.mentionsEveryOne,
|
||||
mentioned: data?.mentioned,
|
||||
messageId: data?.messageId,
|
||||
},
|
||||
null,
|
||||
isIntegration,
|
||||
|
||||
@@ -10,6 +10,12 @@ export class BaileysController {
|
||||
return instance.baileysOnWhatsapp(body?.jid);
|
||||
}
|
||||
|
||||
public async generateMessageID({ instanceName }: InstanceDto) {
|
||||
const instance = this.waMonitor.waInstances[instanceName];
|
||||
|
||||
return instance.generateMessageID();
|
||||
}
|
||||
|
||||
public async profilePictureUrl({ instanceName }: InstanceDto, body: any) {
|
||||
const instance = this.waMonitor.waInstances[instanceName];
|
||||
|
||||
|
||||
@@ -19,6 +19,16 @@ export class BaileysRouter extends RouterBroker {
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.get(this.routerPath('generateMessageID'), ...guards, async (req, res) => {
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => baileysController.generateMessageID(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.post(this.routerPath('profilePictureUrl'), ...guards, async (req, res) => {
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,14 @@ export class ChatwootService {
|
||||
|
||||
private provider: any;
|
||||
|
||||
// Cache para deduplicação de orderMessage (evita mensagens duplicadas)
|
||||
private processedOrderIds: Map<string, number> = new Map();
|
||||
private readonly ORDER_CACHE_TTL_MS = 30000; // 30 segundos
|
||||
|
||||
// Cache para mapeamento LID → Número Normal (resolve problema de @lid)
|
||||
private lidToPhoneMap: Map<string, { phone: string; timestamp: number }> = new Map();
|
||||
private readonly LID_CACHE_TTL_MS = 3600000; // 1 hora
|
||||
|
||||
constructor(
|
||||
private readonly waMonitor: WAMonitoringService,
|
||||
private readonly configService: ConfigService,
|
||||
@@ -632,10 +640,32 @@ export class ChatwootService {
|
||||
public async createConversation(instance: InstanceDto, body: any) {
|
||||
const isLid = body.key.addressingMode === 'lid';
|
||||
const isGroup = body.key.remoteJid.endsWith('@g.us');
|
||||
const phoneNumber = isLid && !isGroup ? body.key.remoteJidAlt : body.key.remoteJid;
|
||||
const { remoteJid } = body.key;
|
||||
const cacheKey = `${instance.instanceName}:createConversation-${remoteJid}`;
|
||||
const lockKey = `${instance.instanceName}:lock:createConversation-${remoteJid}`;
|
||||
let phoneNumber = isLid && !isGroup ? body.key.remoteJidAlt : body.key.remoteJid;
|
||||
let { remoteJid } = body.key;
|
||||
|
||||
// CORREÇÃO LID: Resolve LID para número normal antes de processar
|
||||
if (isLid && !isGroup) {
|
||||
const resolvedPhone = await this.resolveLidToPhone(instance, body.key);
|
||||
|
||||
if (resolvedPhone && resolvedPhone !== remoteJid) {
|
||||
this.logger.verbose(`LID detected and resolved: ${remoteJid} → ${resolvedPhone}`);
|
||||
phoneNumber = resolvedPhone;
|
||||
|
||||
// Salva mapeamento se temos remoteJidAlt
|
||||
if (body.key.remoteJidAlt) {
|
||||
this.saveLidMapping(remoteJid, body.key.remoteJidAlt);
|
||||
}
|
||||
} else if (body.key.remoteJidAlt) {
|
||||
// Se não resolveu mas tem remoteJidAlt, usa ele
|
||||
phoneNumber = body.key.remoteJidAlt;
|
||||
this.saveLidMapping(remoteJid, body.key.remoteJidAlt);
|
||||
this.logger.verbose(`Using remoteJidAlt for LID: ${remoteJid} → ${phoneNumber}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Usa phoneNumber como base para cache (não o LID)
|
||||
const cacheKey = `${instance.instanceName}:createConversation-${phoneNumber}`;
|
||||
const lockKey = `${instance.instanceName}:lock:createConversation-${phoneNumber}`;
|
||||
const maxWaitTime = 5000; // 5 seconds
|
||||
const client = await this.clientCw(instance);
|
||||
if (!client) return null;
|
||||
@@ -943,20 +973,39 @@ export class ChatwootService {
|
||||
|
||||
const sourceReplyId = quotedMsg?.chatwootMessageId || null;
|
||||
|
||||
// Filtra valores null/undefined do content_attributes para evitar erro 406
|
||||
const filteredReplyToIds = Object.fromEntries(
|
||||
Object.entries(replyToIds).filter(([_, value]) => value != null)
|
||||
);
|
||||
|
||||
// Monta o objeto data, incluindo content_attributes apenas se houver dados válidos
|
||||
const messageData: any = {
|
||||
content: content,
|
||||
message_type: messageType,
|
||||
content_type: 'text', // Explicitamente define como texto para Chatwoot 4.x
|
||||
attachments: attachments,
|
||||
private: privateMessage || false,
|
||||
};
|
||||
|
||||
// Adiciona source_id apenas se existir
|
||||
if (sourceId) {
|
||||
messageData.source_id = sourceId;
|
||||
}
|
||||
|
||||
// Adiciona content_attributes apenas se houver dados válidos
|
||||
if (Object.keys(filteredReplyToIds).length > 0) {
|
||||
messageData.content_attributes = filteredReplyToIds;
|
||||
}
|
||||
|
||||
// Adiciona source_reply_id apenas se existir
|
||||
if (sourceReplyId) {
|
||||
messageData.source_reply_id = sourceReplyId.toString();
|
||||
}
|
||||
|
||||
const message = await client.messages.create({
|
||||
accountId: this.provider.accountId,
|
||||
conversationId: conversationId,
|
||||
data: {
|
||||
content: content,
|
||||
message_type: messageType,
|
||||
attachments: attachments,
|
||||
private: privateMessage || false,
|
||||
source_id: sourceId,
|
||||
content_attributes: {
|
||||
...replyToIds,
|
||||
},
|
||||
source_reply_id: sourceReplyId ? sourceReplyId.toString() : null,
|
||||
},
|
||||
data: messageData,
|
||||
});
|
||||
|
||||
if (!message) {
|
||||
@@ -1082,11 +1131,14 @@ export class ChatwootService {
|
||||
if (messageBody && instance) {
|
||||
const replyToIds = await this.getReplyToIds(messageBody, instance);
|
||||
|
||||
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
|
||||
const content = JSON.stringify({
|
||||
...replyToIds,
|
||||
});
|
||||
data.append('content_attributes', content);
|
||||
// Filtra valores null/undefined antes de enviar
|
||||
const filteredReplyToIds = Object.fromEntries(
|
||||
Object.entries(replyToIds).filter(([_, value]) => value != null)
|
||||
);
|
||||
|
||||
if (Object.keys(filteredReplyToIds).length > 0) {
|
||||
const contentAttrs = JSON.stringify(filteredReplyToIds);
|
||||
data.append('content_attributes', contentAttrs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1617,8 +1669,25 @@ export class ChatwootService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use raw SQL to avoid JSON path issues
|
||||
const result = await this.prismaRepository.$executeRaw`
|
||||
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
|
||||
let result: number;
|
||||
|
||||
if (provider === 'mysql') {
|
||||
// MySQL version
|
||||
result = await this.prismaRepository.$executeRaw`
|
||||
UPDATE Message
|
||||
SET
|
||||
chatwootMessageId = ${chatwootMessageIds.messageId},
|
||||
chatwootConversationId = ${chatwootMessageIds.conversationId},
|
||||
chatwootInboxId = ${chatwootMessageIds.inboxId},
|
||||
chatwootContactInboxSourceId = ${chatwootMessageIds.contactInboxSourceId},
|
||||
chatwootIsRead = ${chatwootMessageIds.isRead || false}
|
||||
WHERE instanceId = ${instance.instanceId}
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.id')) = ${key.id}
|
||||
`;
|
||||
} else {
|
||||
// PostgreSQL version
|
||||
result = await this.prismaRepository.$executeRaw`
|
||||
UPDATE "Message"
|
||||
SET
|
||||
"chatwootMessageId" = ${chatwootMessageIds.messageId},
|
||||
@@ -1629,6 +1698,7 @@ export class ChatwootService {
|
||||
WHERE "instanceId" = ${instance.instanceId}
|
||||
AND "key"->>'id' = ${key.id}
|
||||
`;
|
||||
}
|
||||
|
||||
this.logger.verbose(`Update result: ${result} rows affected`);
|
||||
|
||||
@@ -1642,15 +1712,28 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
private async getMessageByKeyId(instance: InstanceDto, keyId: string): Promise<MessageModel> {
|
||||
// Use raw SQL query to avoid JSON path issues with Prisma
|
||||
const messages = await this.prismaRepository.$queryRaw`
|
||||
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
|
||||
let messages: MessageModel[];
|
||||
|
||||
if (provider === 'mysql') {
|
||||
// MySQL version
|
||||
messages = await this.prismaRepository.$queryRaw`
|
||||
SELECT * FROM Message
|
||||
WHERE instanceId = ${instance.instanceId}
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.id')) = ${keyId}
|
||||
LIMIT 1
|
||||
`;
|
||||
} else {
|
||||
// PostgreSQL version
|
||||
messages = await this.prismaRepository.$queryRaw`
|
||||
SELECT * FROM "Message"
|
||||
WHERE "instanceId" = ${instance.instanceId}
|
||||
AND "key"->>'id' = ${keyId}
|
||||
LIMIT 1
|
||||
`;
|
||||
}
|
||||
|
||||
return (messages as MessageModel[])[0] || null;
|
||||
return messages[0] || null;
|
||||
}
|
||||
|
||||
private async getReplyToIds(
|
||||
@@ -1774,6 +1857,8 @@ export class ChatwootService {
|
||||
liveLocationMessage: msg.liveLocationMessage,
|
||||
listMessage: msg.listMessage,
|
||||
listResponseMessage: msg.listResponseMessage,
|
||||
orderMessage: msg.orderMessage,
|
||||
quotedProductMessage: msg.contextInfo?.quotedMessage?.productMessage,
|
||||
viewOnceMessageV2:
|
||||
msg?.message?.viewOnceMessageV2?.message?.imageMessage?.url ||
|
||||
msg?.message?.viewOnceMessageV2?.message?.videoMessage?.url ||
|
||||
@@ -1781,18 +1866,102 @@ export class ChatwootService {
|
||||
};
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
private getMessageContent(types: any) {
|
||||
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||
|
||||
let result = typeKey ? types[typeKey] : undefined;
|
||||
|
||||
// Remove externalAdReplyBody| in Chatwoot (Already Have)
|
||||
// Remove externalAdReplyBody| in Chatwoot
|
||||
if (result && typeof result === 'string' && result.includes('externalAdReplyBody|')) {
|
||||
result = result.split('externalAdReplyBody|').filter(Boolean).join('');
|
||||
}
|
||||
|
||||
// Tratamento de Pedidos do Catálogo (WhatsApp Business Catalog)
|
||||
if (typeKey === 'orderMessage' && result.orderId) {
|
||||
const now = Date.now();
|
||||
// Limpa entradas antigas do cache
|
||||
this.processedOrderIds.forEach((timestamp, id) => {
|
||||
if (now - timestamp > this.ORDER_CACHE_TTL_MS) {
|
||||
this.processedOrderIds.delete(id);
|
||||
}
|
||||
});
|
||||
// Verifica se já processou este orderId
|
||||
if (this.processedOrderIds.has(result.orderId)) {
|
||||
return undefined; // Ignora duplicado
|
||||
}
|
||||
this.processedOrderIds.set(result.orderId, now);
|
||||
}
|
||||
// Tratamento de Produto citado (WhatsApp Desktop)
|
||||
if (typeKey === 'quotedProductMessage' && result?.product) {
|
||||
const product = result.product;
|
||||
|
||||
// Extrai preço
|
||||
let rawPrice = 0;
|
||||
const amount = product.priceAmount1000;
|
||||
|
||||
if (Long.isLong(amount)) {
|
||||
rawPrice = amount.toNumber();
|
||||
} else if (amount && typeof amount === 'object' && 'low' in amount) {
|
||||
rawPrice = Long.fromValue(amount).toNumber();
|
||||
} else if (typeof amount === 'number') {
|
||||
rawPrice = amount;
|
||||
}
|
||||
|
||||
const price = (rawPrice / 1000).toLocaleString('pt-BR', {
|
||||
style: 'currency',
|
||||
currency: product.currencyCode || 'BRL',
|
||||
});
|
||||
|
||||
const productTitle = product.title || 'Produto do catálogo';
|
||||
const productId = product.productId || 'N/A';
|
||||
|
||||
return (
|
||||
`🛒 *PRODUTO DO CATÁLOGO (Desktop)*\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━\n` +
|
||||
`📦 *Produto:* ${productTitle}\n` +
|
||||
`💰 *Preço:* ${price}\n` +
|
||||
`🆔 *Código:* ${productId}\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━\n` +
|
||||
`_Cliente perguntou: "${types.conversation || 'Me envia este produto?'}"_`
|
||||
);
|
||||
}
|
||||
if (typeKey === 'orderMessage') {
|
||||
// Extrai o valor - pode ser Long, objeto {low, high}, ou número direto
|
||||
let rawPrice = 0;
|
||||
const amount = result.totalAmount1000;
|
||||
|
||||
if (Long.isLong(amount)) {
|
||||
rawPrice = amount.toNumber();
|
||||
} else if (amount && typeof amount === 'object' && 'low' in amount) {
|
||||
// Formato {low: number, high: number, unsigned: boolean}
|
||||
rawPrice = Long.fromValue(amount).toNumber();
|
||||
} else if (typeof amount === 'number') {
|
||||
rawPrice = amount;
|
||||
}
|
||||
|
||||
const price = (rawPrice / 1000).toLocaleString('pt-BR', {
|
||||
style: 'currency',
|
||||
currency: result.totalCurrencyCode || 'BRL',
|
||||
});
|
||||
|
||||
const itemCount = result.itemCount || 1;
|
||||
const orderTitle = result.orderTitle || 'Produto do catálogo';
|
||||
const orderId = result.orderId || 'N/A';
|
||||
|
||||
return (
|
||||
`🛒 *NOVO PEDIDO NO CATÁLOGO*\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━\n` +
|
||||
`📦 *Produto:* ${orderTitle}\n` +
|
||||
`📊 *Quantidade:* ${itemCount}\n` +
|
||||
`💰 *Total:* ${price}\n` +
|
||||
`🆔 *Pedido:* #${orderId}\n` +
|
||||
`━━━━━━━━━━━━━━━━━━━━━\n` +
|
||||
`_Responda para atender este pedido!_`
|
||||
);
|
||||
}
|
||||
|
||||
if (typeKey === 'locationMessage' || typeKey === 'liveLocationMessage') {
|
||||
const latitude = result.degreesLatitude;
|
||||
const longitude = result.degreesLongitude;
|
||||
@@ -1993,6 +2162,29 @@ export class ChatwootService {
|
||||
}
|
||||
}
|
||||
|
||||
// CORREÇÃO LID: Resolve LID para número normal antes de processar evento
|
||||
if (body?.key?.remoteJid && body.key.remoteJid.includes('@lid') && !body.key.remoteJid.endsWith('@g.us')) {
|
||||
const originalJid = body.key.remoteJid;
|
||||
const resolvedPhone = await this.resolveLidToPhone(instance, body.key);
|
||||
|
||||
if (resolvedPhone && resolvedPhone !== originalJid) {
|
||||
this.logger.verbose(`Event LID resolved: ${originalJid} → ${resolvedPhone}`);
|
||||
body.key.remoteJid = resolvedPhone;
|
||||
|
||||
// Salva mapeamento se temos remoteJidAlt
|
||||
if (body.key.remoteJidAlt) {
|
||||
this.saveLidMapping(originalJid, body.key.remoteJidAlt);
|
||||
}
|
||||
} else if (body.key.remoteJidAlt && !body.key.remoteJidAlt.includes('@lid')) {
|
||||
// Se não resolveu mas tem remoteJidAlt válido, usa ele
|
||||
this.logger.verbose(`Using remoteJidAlt for event: ${originalJid} → ${body.key.remoteJidAlt}`);
|
||||
body.key.remoteJid = body.key.remoteJidAlt;
|
||||
this.saveLidMapping(originalJid, body.key.remoteJidAlt);
|
||||
} else {
|
||||
this.logger.warn(`Could not resolve LID for event, keeping original: ${originalJid}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (event === 'messages.upsert' || event === 'send.message') {
|
||||
this.logger.info(`[${event}] New message received - Instance: ${JSON.stringify(body, null, 2)}`);
|
||||
if (body.key.remoteJid === 'status@broadcast') {
|
||||
@@ -2537,6 +2729,82 @@ export class ChatwootService {
|
||||
return remoteJid.replace(/:\d+/, '').split('@')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa entradas antigas do cache de mapeamento LID
|
||||
*/
|
||||
private cleanLidCache() {
|
||||
const now = Date.now();
|
||||
this.lidToPhoneMap.forEach((value, lid) => {
|
||||
if (now - value.timestamp > this.LID_CACHE_TTL_MS) {
|
||||
this.lidToPhoneMap.delete(lid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Salva mapeamento LID → Número Normal
|
||||
*/
|
||||
private saveLidMapping(lid: string, phoneNumber: string) {
|
||||
if (!lid || !phoneNumber || !lid.includes('@lid')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleanLidCache();
|
||||
this.lidToPhoneMap.set(lid, {
|
||||
phone: phoneNumber,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
this.logger.verbose(`LID mapping saved: ${lid} → ${phoneNumber}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve LID para Número Normal
|
||||
* Retorna o número normal se encontrado, ou o LID original se não encontrado
|
||||
*/
|
||||
private async resolveLidToPhone(instance: InstanceDto, messageKey: any): Promise<string | null> {
|
||||
const { remoteJid, remoteJidAlt } = messageKey;
|
||||
|
||||
// Se não for LID, retorna o próprio remoteJid
|
||||
if (!remoteJid || !remoteJid.includes('@lid')) {
|
||||
return remoteJid;
|
||||
}
|
||||
|
||||
// 1. Tenta buscar no cache
|
||||
const cached = this.lidToPhoneMap.get(remoteJid);
|
||||
if (cached) {
|
||||
this.logger.verbose(`LID resolved from cache: ${remoteJid} → ${cached.phone}`);
|
||||
return cached.phone;
|
||||
}
|
||||
|
||||
// 2. Se tem remoteJidAlt (número alternativo), usa ele e salva no cache
|
||||
if (remoteJidAlt && !remoteJidAlt.includes('@lid')) {
|
||||
this.saveLidMapping(remoteJid, remoteJidAlt);
|
||||
this.logger.verbose(`LID resolved from remoteJidAlt: ${remoteJid} → ${remoteJidAlt}`);
|
||||
return remoteJidAlt;
|
||||
}
|
||||
|
||||
// 3. Tenta buscar no banco de dados do Chatwoot
|
||||
try {
|
||||
const lidIdentifier = this.normalizeJidIdentifier(remoteJid);
|
||||
const contact = await this.findContactByIdentifier(instance, lidIdentifier);
|
||||
|
||||
if (contact && contact.phone_number) {
|
||||
// Converte +554498860240 → 554498860240@s.whatsapp.net
|
||||
const phoneNumber = contact.phone_number.replace('+', '') + '@s.whatsapp.net';
|
||||
this.saveLidMapping(remoteJid, phoneNumber);
|
||||
this.logger.verbose(`LID resolved from database: ${remoteJid} → ${phoneNumber}`);
|
||||
return phoneNumber;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.warn(`Error resolving LID from database: ${error}`);
|
||||
}
|
||||
|
||||
// 4. Se não encontrou, retorna null (será necessário criar novo contato)
|
||||
this.logger.warn(`Could not resolve LID: ${remoteJid}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
public startImportHistoryMessages(instance: InstanceDto) {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
|
||||
@@ -368,6 +368,60 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
|
||||
sendTelemetry('/message/sendWhatsAppAudio');
|
||||
}
|
||||
|
||||
if (message.type === 'file' || message.type === 'embed') {
|
||||
const content = message.content as { url?: string; name?: string } | undefined;
|
||||
if (!content?.url) {
|
||||
sendTelemetry('/message/sendMediaMissingUrl');
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaUrl = content.url;
|
||||
const mediaType = this.getMediaType(mediaUrl);
|
||||
|
||||
let fileName = content.name;
|
||||
if (!fileName) {
|
||||
try {
|
||||
const urlObj = new URL(mediaUrl);
|
||||
const path = urlObj.pathname || '';
|
||||
const candidate = path.split('/').pop() || '';
|
||||
if (candidate && candidate.includes('.')) {
|
||||
fileName = candidate;
|
||||
}
|
||||
} catch {
|
||||
// Ignore URL parsing failures
|
||||
}
|
||||
|
||||
if (!fileName) {
|
||||
fileName = mediaType && mediaType !== 'document' ? `media.${mediaType}` : 'attachment';
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaType === 'audio') {
|
||||
await instance.audioWhatsapp(
|
||||
{
|
||||
number: session.remoteJid,
|
||||
delay: settings?.delayMessage || 1000,
|
||||
encoding: true,
|
||||
audio: mediaUrl,
|
||||
},
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
await instance.mediaMessage(
|
||||
{
|
||||
number: session.remoteJid,
|
||||
delay: settings?.delayMessage || 1000,
|
||||
mediatype: mediaType || 'document',
|
||||
media: mediaUrl,
|
||||
fileName,
|
||||
},
|
||||
null,
|
||||
false,
|
||||
);
|
||||
}
|
||||
sendTelemetry('/message/sendMedia');
|
||||
}
|
||||
|
||||
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
|
||||
|
||||
if (wait) {
|
||||
|
||||
@@ -162,6 +162,7 @@ export class EventController {
|
||||
'CALL',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'MESSAGING_HISTORY_SET',
|
||||
'REMOVE_INSTANCE',
|
||||
'LOGOUT_INSTANCE',
|
||||
'INSTANCE_CREATE',
|
||||
|
||||
@@ -126,7 +126,9 @@ export class SqsController extends EventController implements EventControllerInt
|
||||
? 'singlequeue'
|
||||
: `${event.replace('.', '_').toLowerCase()}`;
|
||||
const queueName = `${prefixName}_${eventFormatted}.fifo`;
|
||||
const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
||||
const rawBaseUrl = sqsConfig.BASE_URL || `https://sqs.${sqsConfig.REGION}.amazonaws.com`;
|
||||
const baseUrl = rawBaseUrl.replace(/\/+$/, '');
|
||||
const sqsUrl = `${baseUrl}/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
||||
|
||||
const message = {
|
||||
...(extra ?? {}),
|
||||
|
||||
@@ -124,9 +124,20 @@ export class WebhookController extends EventController implements EventControlle
|
||||
|
||||
try {
|
||||
if (instance?.enabled && regex.test(instance.url)) {
|
||||
// Add custom headers for better webhook tracking and debugging
|
||||
const enhancedHeaders = {
|
||||
...webhookHeaders,
|
||||
'Content-Type': 'application/json',
|
||||
'X-Instance-ID': this.monitor.waInstances[instanceName].instanceId,
|
||||
'X-Instance-Name': instanceName,
|
||||
'X-Event-Type': event,
|
||||
'X-Timestamp': Date.now().toString(),
|
||||
'User-Agent': 'EvolutionAPI-Webhook/2.3.7',
|
||||
};
|
||||
|
||||
const httpService = axios.create({
|
||||
baseURL,
|
||||
headers: webhookHeaders as Record<string, string> | undefined,
|
||||
headers: enhancedHeaders as Record<string, string>,
|
||||
timeout: webhookConfig.REQUEST?.TIMEOUT_MS ?? 30000,
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { RouterBroker } from '@api/abstract/abstract.router';
|
||||
import {
|
||||
ArchiveChatDto,
|
||||
BlockUserDto,
|
||||
DecryptPollVoteDto,
|
||||
DeleteMessage,
|
||||
getBase64FromMediaMessageDto,
|
||||
MarkChatUnreadDto,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
archiveChatSchema,
|
||||
blockUserSchema,
|
||||
contactValidateSchema,
|
||||
decryptPollVoteSchema,
|
||||
deleteMessageSchema,
|
||||
markChatUnreadSchema,
|
||||
messageUpSchema,
|
||||
@@ -281,6 +283,26 @@ export class ChatRouter extends RouterBroker {
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.post(this.routerPath('getPollVote'), ...guards, async (req, res) => {
|
||||
const response = await this.dataValidate<DecryptPollVoteDto>({
|
||||
request: req,
|
||||
schema: decryptPollVoteSchema,
|
||||
ClassRef: DecryptPollVoteDto,
|
||||
execute: (instance, data) => chatController.decryptPollVote(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.post(this.routerPath('findChannels'), ...guards, async (req, res) => {
|
||||
const response = await this.dataValidate({
|
||||
request: req,
|
||||
schema: contactValidateSchema,
|
||||
ClassRef: Query<Contact>,
|
||||
execute: (instance, query) => chatController.fetchChannels(instance, query as any),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { TypebotService } from '@api/integrations/chatbot/typebot/services/typeb
|
||||
import { PrismaRepository, Query } from '@api/repository/repository.service';
|
||||
import { eventManager, waMonitor } from '@api/server.module';
|
||||
import { Events, wa } from '@api/types/wa.types';
|
||||
import { Auth, Chatwoot, ConfigService, HttpServer, Proxy } from '@config/env.config';
|
||||
import { Auth, Chatwoot, ConfigService, Database, HttpServer, Proxy } from '@config/env.config';
|
||||
import { Logger } from '@config/logger.config';
|
||||
import { NotFoundException } from '@exceptions';
|
||||
import { Contact, Message, Prisma } from '@prisma/client';
|
||||
@@ -731,6 +731,72 @@ export class ChannelStartupService {
|
||||
where['remoteJid'] = remoteJid;
|
||||
}
|
||||
|
||||
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
|
||||
const limit = query?.take ? Prisma.sql`LIMIT ${query.take}` : Prisma.sql``;
|
||||
const offset = query?.skip ? Prisma.sql`OFFSET ${query.skip}` : Prisma.sql``;
|
||||
|
||||
let results: any[];
|
||||
|
||||
if (provider === 'mysql') {
|
||||
// MySQL version
|
||||
const timestampFilterMysql =
|
||||
query?.where?.messageTimestamp?.gte && query?.where?.messageTimestamp?.lte
|
||||
? Prisma.sql`
|
||||
AND Message.messageTimestamp >= ${Math.floor(new Date(query.where.messageTimestamp.gte).getTime() / 1000)}
|
||||
AND Message.messageTimestamp <= ${Math.floor(new Date(query.where.messageTimestamp.lte).getTime() / 1000)}`
|
||||
: Prisma.sql``;
|
||||
|
||||
results = await this.prismaRepository.$queryRaw`
|
||||
SELECT
|
||||
Contact.id as contactId,
|
||||
JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid')) as remoteJid,
|
||||
CASE
|
||||
WHEN JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid')) LIKE '%@g.us' THEN COALESCE(Chat.name, Contact.pushName)
|
||||
ELSE COALESCE(Contact.pushName, Message.pushName)
|
||||
END as pushName,
|
||||
Contact.profilePicUrl,
|
||||
COALESCE(
|
||||
FROM_UNIXTIME(Message.messageTimestamp),
|
||||
Contact.updatedAt
|
||||
) as updatedAt,
|
||||
Chat.name as chatName,
|
||||
Chat.createdAt as windowStart,
|
||||
DATE_ADD(Chat.createdAt, INTERVAL 24 HOUR) as windowExpires,
|
||||
Chat.unreadMessages as unreadMessages,
|
||||
CASE WHEN DATE_ADD(Chat.createdAt, INTERVAL 24 HOUR) > NOW() THEN 1 ELSE 0 END as windowActive,
|
||||
Message.id AS lastMessageId,
|
||||
Message.key AS lastMessage_key,
|
||||
CASE
|
||||
WHEN JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.fromMe')) = 'true' THEN 'Você'
|
||||
ELSE Message.pushName
|
||||
END AS lastMessagePushName,
|
||||
Message.participant AS lastMessageParticipant,
|
||||
Message.messageType AS lastMessageMessageType,
|
||||
Message.message AS lastMessageMessage,
|
||||
Message.contextInfo AS lastMessageContextInfo,
|
||||
Message.source AS lastMessageSource,
|
||||
Message.messageTimestamp AS lastMessageMessageTimestamp,
|
||||
Message.instanceId AS lastMessageInstanceId,
|
||||
Message.sessionId AS lastMessageSessionId,
|
||||
Message.status AS lastMessageStatus
|
||||
FROM Message
|
||||
LEFT JOIN Contact ON Contact.remoteJid = JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid')) AND Contact.instanceId = Message.instanceId
|
||||
LEFT JOIN Chat ON Chat.remoteJid = JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid')) AND Chat.instanceId = Message.instanceId
|
||||
WHERE Message.instanceId = ${this.instanceId}
|
||||
${remoteJid ? Prisma.sql`AND JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid')) = ${remoteJid}` : Prisma.sql``}
|
||||
${timestampFilterMysql}
|
||||
AND Message.messageTimestamp = (
|
||||
SELECT MAX(m2.messageTimestamp)
|
||||
FROM Message m2
|
||||
WHERE JSON_UNQUOTE(JSON_EXTRACT(m2.key, '$.remoteJid')) = JSON_UNQUOTE(JSON_EXTRACT(Message.key, '$.remoteJid'))
|
||||
AND m2.instanceId = Message.instanceId
|
||||
)
|
||||
ORDER BY updatedAt DESC
|
||||
${limit}
|
||||
${offset};
|
||||
`;
|
||||
} else {
|
||||
// PostgreSQL version
|
||||
const timestampFilter =
|
||||
query?.where?.messageTimestamp?.gte && query?.where?.messageTimestamp?.lte
|
||||
? Prisma.sql`
|
||||
@@ -738,10 +804,7 @@ export class ChannelStartupService {
|
||||
AND "Message"."messageTimestamp" <= ${Math.floor(new Date(query.where.messageTimestamp.lte).getTime() / 1000)}`
|
||||
: Prisma.sql``;
|
||||
|
||||
const limit = query?.take ? Prisma.sql`LIMIT ${query.take}` : Prisma.sql``;
|
||||
const offset = query?.skip ? Prisma.sql`OFFSET ${query.skip}` : Prisma.sql``;
|
||||
|
||||
const results = await this.prismaRepository.$queryRaw`
|
||||
results = await this.prismaRepository.$queryRaw`
|
||||
WITH rankedMessages AS (
|
||||
SELECT DISTINCT ON ("Message"."key"->>'remoteJid')
|
||||
"Contact"."id" as "contactId",
|
||||
@@ -788,6 +851,7 @@ export class ChannelStartupService {
|
||||
${limit}
|
||||
${offset};
|
||||
`;
|
||||
}
|
||||
|
||||
if (results && isArray(results) && results.length > 0) {
|
||||
const mappedResults = results.map((contact) => {
|
||||
|
||||
@@ -91,6 +91,7 @@ export type EventsRabbitmq = {
|
||||
CALL: boolean;
|
||||
TYPEBOT_START: boolean;
|
||||
TYPEBOT_CHANGE_STATUS: boolean;
|
||||
MESSAGING_HISTORY_SET: boolean;
|
||||
};
|
||||
|
||||
export type Rabbitmq = {
|
||||
@@ -121,6 +122,7 @@ export type Sqs = {
|
||||
SECRET_ACCESS_KEY: string;
|
||||
ACCOUNT_ID: string;
|
||||
REGION: string;
|
||||
BASE_URL: string;
|
||||
MAX_PAYLOAD_SIZE: number;
|
||||
EVENTS: {
|
||||
APPLICATION_STARTUP: boolean;
|
||||
@@ -150,6 +152,7 @@ export type Sqs = {
|
||||
SEND_MESSAGE: boolean;
|
||||
TYPEBOT_CHANGE_STATUS: boolean;
|
||||
TYPEBOT_START: boolean;
|
||||
MESSAGING_HISTORY_SET: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -223,6 +226,7 @@ export type EventsWebhook = {
|
||||
CALL: boolean;
|
||||
TYPEBOT_START: boolean;
|
||||
TYPEBOT_CHANGE_STATUS: boolean;
|
||||
MESSAGING_HISTORY_SET: boolean;
|
||||
ERRORS: boolean;
|
||||
ERRORS_WEBHOOK: string;
|
||||
};
|
||||
@@ -256,6 +260,7 @@ export type EventsPusher = {
|
||||
CALL: boolean;
|
||||
TYPEBOT_START: boolean;
|
||||
TYPEBOT_CHANGE_STATUS: boolean;
|
||||
MESSAGING_HISTORY_SET: boolean;
|
||||
};
|
||||
|
||||
export type ApiKey = { KEY: string };
|
||||
@@ -313,6 +318,7 @@ export type Webhook = {
|
||||
};
|
||||
export type Pusher = { ENABLED: boolean; GLOBAL?: GlobalPusher; EVENTS: EventsPusher };
|
||||
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
|
||||
export type Baileys = { VERSION?: string };
|
||||
export type QrCode = { LIMIT: number; COLOR: string };
|
||||
export type Typebot = { ENABLED: boolean; API_VERSION: string; SEND_MEDIA_BASE64: boolean };
|
||||
export type Chatwoot = {
|
||||
@@ -410,6 +416,7 @@ export interface Env {
|
||||
WEBHOOK: Webhook;
|
||||
PUSHER: Pusher;
|
||||
CONFIG_SESSION_PHONE: ConfigSessionPhone;
|
||||
BAILEYS: Baileys;
|
||||
QRCODE: QrCode;
|
||||
TYPEBOT: Typebot;
|
||||
CHATWOOT: Chatwoot;
|
||||
@@ -537,6 +544,7 @@ export class ConfigService {
|
||||
CALL: process.env?.RABBITMQ_EVENTS_CALL === 'true',
|
||||
TYPEBOT_START: process.env?.RABBITMQ_EVENTS_TYPEBOT_START === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.RABBITMQ_EVENTS_MESSAGING_HISTORY_SET === 'true',
|
||||
},
|
||||
},
|
||||
NATS: {
|
||||
@@ -574,6 +582,7 @@ export class ConfigService {
|
||||
CALL: process.env?.NATS_EVENTS_CALL === 'true',
|
||||
TYPEBOT_START: process.env?.NATS_EVENTS_TYPEBOT_START === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.NATS_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.NATS_EVENTS_MESSAGING_HISTORY_SET === 'true',
|
||||
},
|
||||
},
|
||||
SQS: {
|
||||
@@ -585,6 +594,7 @@ export class ConfigService {
|
||||
SECRET_ACCESS_KEY: process.env.SQS_SECRET_ACCESS_KEY || '',
|
||||
ACCOUNT_ID: process.env.SQS_ACCOUNT_ID || '',
|
||||
REGION: process.env.SQS_REGION || '',
|
||||
BASE_URL: process.env.SQS_BASE_URL || '',
|
||||
MAX_PAYLOAD_SIZE: Number.parseInt(process.env.SQS_MAX_PAYLOAD_SIZE ?? '1048576'),
|
||||
EVENTS: {
|
||||
APPLICATION_STARTUP: process.env?.SQS_GLOBAL_APPLICATION_STARTUP === 'true',
|
||||
@@ -614,6 +624,7 @@ export class ConfigService {
|
||||
SEND_MESSAGE: process.env?.SQS_GLOBAL_SEND_MESSAGE === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.SQS_GLOBAL_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
TYPEBOT_START: process.env?.SQS_GLOBAL_TYPEBOT_START === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.SQS_GLOBAL_MESSAGING_HISTORY_SET === 'true',
|
||||
},
|
||||
},
|
||||
KAFKA: {
|
||||
@@ -657,6 +668,7 @@ export class ConfigService {
|
||||
CALL: process.env?.KAFKA_EVENTS_CALL === 'true',
|
||||
TYPEBOT_START: process.env?.KAFKA_EVENTS_TYPEBOT_START === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.KAFKA_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.KAFKA_EVENTS_MESSAGING_HISTORY_SET === 'true',
|
||||
},
|
||||
SASL:
|
||||
process.env?.KAFKA_SASL_ENABLED === 'true'
|
||||
@@ -722,6 +734,7 @@ export class ConfigService {
|
||||
CALL: process.env?.PUSHER_EVENTS_CALL === 'true',
|
||||
TYPEBOT_START: process.env?.PUSHER_EVENTS_TYPEBOT_START === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.PUSHER_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.PUSHER_EVENTS_MESSAGING_HISTORY_SET === 'true',
|
||||
},
|
||||
},
|
||||
WA_BUSINESS: {
|
||||
@@ -779,6 +792,7 @@ export class ConfigService {
|
||||
CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true',
|
||||
TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true',
|
||||
TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
|
||||
MESSAGING_HISTORY_SET: process.env?.WEBHOOK_EVENTS_MESSAGING_HISTORY_SET === 'true',
|
||||
ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true',
|
||||
ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '',
|
||||
},
|
||||
@@ -800,6 +814,9 @@ export class ConfigService {
|
||||
CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API',
|
||||
NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome',
|
||||
},
|
||||
BAILEYS: {
|
||||
VERSION: process.env?.CONFIG_BAILEYS_VERSION,
|
||||
},
|
||||
QRCODE: {
|
||||
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
|
||||
COLOR: process.env.QRCODE_COLOR || '#198754',
|
||||
|
||||
@@ -35,7 +35,12 @@ function formatBRNumber(jid: string) {
|
||||
export function createJid(number: string): string {
|
||||
number = number.replace(/:\d+/, '');
|
||||
|
||||
if (number.includes('@g.us') || number.includes('@s.whatsapp.net') || number.includes('@lid')) {
|
||||
if (
|
||||
number.includes('@g.us') ||
|
||||
number.includes('@s.whatsapp.net') ||
|
||||
number.includes('@lid') ||
|
||||
number.includes('@newsletter')
|
||||
) {
|
||||
return number;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,51 @@
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import { fetchLatestBaileysVersion, WAVersion } from 'baileys';
|
||||
|
||||
export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>) => {
|
||||
import { CacheService } from '../api/services/cache.service';
|
||||
import { CacheEngine } from '../cache/cacheengine';
|
||||
import { Baileys, configService } from '../config/env.config';
|
||||
|
||||
// Cache keys
|
||||
const CACHE_KEY_WHATSAPP_WEB_VERSION = 'whatsapp_web_version';
|
||||
const CACHE_KEY_BAILEYS_FALLBACK_VERSION = 'baileys_fallback_version';
|
||||
|
||||
// Cache TTL (1 hour in seconds)
|
||||
const CACHE_TTL_SECONDS = 3600;
|
||||
|
||||
const MODULE_NAME = 'whatsapp-version';
|
||||
|
||||
export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>, cache?: CacheService) => {
|
||||
// Check if manual version is set via configuration
|
||||
const baileysConfig = configService.get<Baileys>('BAILEYS');
|
||||
const manualVersion = baileysConfig?.VERSION;
|
||||
|
||||
if (manualVersion) {
|
||||
const versionParts = manualVersion.split('.').map(Number);
|
||||
if (versionParts.length === 3 && !versionParts.some(isNaN)) {
|
||||
return {
|
||||
version: versionParts as WAVersion,
|
||||
isLatest: false,
|
||||
isManual: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let versionCache = cache || null;
|
||||
|
||||
if (!versionCache) {
|
||||
// Cache estático para versões do WhatsApp Web e fallback do Baileys (fallback se não for passado via parâmetro)
|
||||
const cacheEngine = new CacheEngine(configService, MODULE_NAME);
|
||||
const engine = cacheEngine.getEngine();
|
||||
const defaultVersionCache = new CacheService(engine);
|
||||
versionCache = defaultVersionCache;
|
||||
}
|
||||
|
||||
// Check cache for WhatsApp Web version
|
||||
const cachedWaVersion = await versionCache.get(CACHE_KEY_WHATSAPP_WEB_VERSION);
|
||||
if (cachedWaVersion) {
|
||||
return cachedWaVersion;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await axios.get('https://web.whatsapp.com/sw.js', {
|
||||
...options,
|
||||
@@ -12,26 +56,51 @@ export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>) =
|
||||
const match = data.match(regex);
|
||||
|
||||
if (!match?.[1]) {
|
||||
return {
|
||||
// Check cache for Baileys fallback version
|
||||
const cachedFallback = await versionCache.get(CACHE_KEY_BAILEYS_FALLBACK_VERSION);
|
||||
if (cachedFallback) {
|
||||
return cachedFallback;
|
||||
}
|
||||
|
||||
// Fetch and cache Baileys fallback version
|
||||
const fallbackVersion = {
|
||||
version: (await fetchLatestBaileysVersion()).version as WAVersion,
|
||||
isLatest: false,
|
||||
error: {
|
||||
message: 'Could not find client revision in the fetched content',
|
||||
},
|
||||
};
|
||||
|
||||
await versionCache.set(CACHE_KEY_BAILEYS_FALLBACK_VERSION, fallbackVersion, CACHE_TTL_SECONDS);
|
||||
return fallbackVersion;
|
||||
}
|
||||
|
||||
const clientRevision = match[1];
|
||||
|
||||
return {
|
||||
const result = {
|
||||
version: [2, 3000, +clientRevision] as WAVersion,
|
||||
isLatest: true,
|
||||
};
|
||||
|
||||
// Cache the successful result
|
||||
await versionCache.set(CACHE_KEY_WHATSAPP_WEB_VERSION, result, CACHE_TTL_SECONDS);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return {
|
||||
// Check cache for Baileys fallback version
|
||||
const cachedFallback = await versionCache.get(CACHE_KEY_BAILEYS_FALLBACK_VERSION);
|
||||
if (cachedFallback) {
|
||||
return cachedFallback;
|
||||
}
|
||||
|
||||
// Fetch and cache Baileys fallback version
|
||||
const fallbackVersion = {
|
||||
version: (await fetchLatestBaileysVersion()).version as WAVersion,
|
||||
isLatest: false,
|
||||
error,
|
||||
};
|
||||
|
||||
await versionCache.set(CACHE_KEY_BAILEYS_FALLBACK_VERSION, fallbackVersion, CACHE_TTL_SECONDS);
|
||||
return fallbackVersion;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ const getTypeMessage = (msg: any) => {
|
||||
conversation: msg?.message?.conversation,
|
||||
extendedTextMessage: msg?.message?.extendedTextMessage?.text,
|
||||
contactMessage: msg?.message?.contactMessage?.displayName,
|
||||
locationMessage: msg?.message?.locationMessage?.degreesLatitude.toString(),
|
||||
locationMessage: msg?.message?.locationMessage?.degreesLatitude?.toString(),
|
||||
viewOnceMessageV2:
|
||||
msg?.message?.viewOnceMessageV2?.message?.imageMessage?.url ||
|
||||
msg?.message?.viewOnceMessageV2?.message?.videoMessage?.url ||
|
||||
@@ -49,9 +49,18 @@ const getTypeMessage = (msg: any) => {
|
||||
: ''
|
||||
}`
|
||||
: undefined,
|
||||
externalAdReplyBody: msg?.contextInfo?.externalAdReply?.body
|
||||
|
||||
// --- FIX FACEBOOK ADS START ---
|
||||
externalAdReplyBody: msg?.message?.extendedTextMessage?.contextInfo?.externalAdReply?.body
|
||||
? `externalAdReplyBody|${msg.message.extendedTextMessage.contextInfo.externalAdReply.body}`
|
||||
: msg?.message?.extendedTextMessage?.contextInfo?.externalAdReply?.title
|
||||
? `externalAdReplyBody|${msg.message.extendedTextMessage.contextInfo.externalAdReply.title}`
|
||||
: msg?.contextInfo?.externalAdReply?.body
|
||||
? `externalAdReplyBody|${msg.contextInfo.externalAdReply.body}`
|
||||
: msg?.contextInfo?.externalAdReply?.title
|
||||
? `externalAdReplyBody|${msg.contextInfo.externalAdReply.title}`
|
||||
: undefined,
|
||||
// --- FIX FACEBOOK ADS END ---
|
||||
};
|
||||
|
||||
const messageType = Object.keys(types).find((key) => types[key] !== undefined) || 'unknown';
|
||||
@@ -60,7 +69,9 @@ const getTypeMessage = (msg: any) => {
|
||||
};
|
||||
|
||||
const getMessageContent = (types: any) => {
|
||||
const typeKey = Object.keys(types).find((key) => key !== 'externalAdReplyBody' && types[key] !== undefined);
|
||||
const typeKey = Object.keys(types).find(
|
||||
(key) => key !== 'externalAdReplyBody' && key !== 'messageType' && types[key] !== undefined,
|
||||
);
|
||||
|
||||
let result = typeKey ? types[typeKey] : undefined;
|
||||
|
||||
@@ -73,7 +84,6 @@ const getMessageContent = (types: any) => {
|
||||
|
||||
export const getConversationMessage = (msg: any) => {
|
||||
const types = getTypeMessage(msg);
|
||||
|
||||
const messageContent = getMessageContent(types);
|
||||
|
||||
return messageContent ?? '';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { prismaRepository } from '@api/server.module';
|
||||
import { configService, Database } from '@config/env.config';
|
||||
import { Logger } from '@config/logger.config';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const logger = new Logger('OnWhatsappCache');
|
||||
@@ -164,9 +165,28 @@ export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) {
|
||||
logger.verbose(
|
||||
`[saveOnWhatsappCache] Register does not exist, creating: remoteJid=${remoteJid}, jidOptions=${dataPayload.jidOptions}, lid=${dataPayload.lid}`,
|
||||
);
|
||||
try {
|
||||
await prismaRepository.isOnWhatsapp.create({
|
||||
data: dataPayload,
|
||||
});
|
||||
} catch (error: any) {
|
||||
// Check for unique constraint violation (Prisma error code P2002)
|
||||
if (
|
||||
error instanceof Prisma.PrismaClientKnownRequestError &&
|
||||
error.code === 'P2002' &&
|
||||
(error.meta?.target as string[])?.includes('remoteJid')
|
||||
) {
|
||||
logger.verbose(
|
||||
`[saveOnWhatsappCache] Race condition detected for ${remoteJid}, updating existing record instead.`,
|
||||
);
|
||||
await prismaRepository.isOnWhatsapp.update({
|
||||
where: { remoteJid: remoteJid },
|
||||
data: dataPayload,
|
||||
});
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Loga o erro mas não para a execução dos outros promises
|
||||
|
||||
@@ -86,6 +86,7 @@ export const instanceSchema: JSONSchema7 = {
|
||||
'CALL',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'MESSAGING_HISTORY_SET',
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -123,6 +124,7 @@ export const instanceSchema: JSONSchema7 = {
|
||||
'CALL',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'MESSAGING_HISTORY_SET',
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -160,6 +162,7 @@ export const instanceSchema: JSONSchema7 = {
|
||||
'CALL',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'MESSAGING_HISTORY_SET',
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -197,6 +200,7 @@ export const instanceSchema: JSONSchema7 = {
|
||||
'CALL',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'MESSAGING_HISTORY_SET',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -447,3 +447,25 @@ export const buttonsMessageSchema: JSONSchema7 = {
|
||||
},
|
||||
required: ['number'],
|
||||
};
|
||||
|
||||
export const decryptPollVoteSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
message: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
key: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
},
|
||||
required: ['id'],
|
||||
},
|
||||
},
|
||||
required: ['key'],
|
||||
},
|
||||
remoteJid: { type: 'string' },
|
||||
},
|
||||
required: ['message', 'remoteJid'],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user