diff --git a/package.json b/package.json index 219b74d..7bcec8c 100755 --- a/package.json +++ b/package.json @@ -60,13 +60,14 @@ "dotenv": "^16.4.7", "fastify": "^5.2.1", "handlebars": "^4.7.8", - "node-jose": "^2.2.0", + "nestjs-telegraf": "^2.8.1", "nodemailer": "^6.9.16", "passport-jwt": "^4.0.1", "pg": "^8.13.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "slugify": "^1.6.6", + "telegraf": "^4.16.3", "typeorm": "^0.3.20" }, "devDependencies": { @@ -78,7 +79,6 @@ "@types/bcrypt": "^5.0.2", "@types/jest": "^29.5.14", "@types/node": "^20.17.14", - "@types/node-jose": "^1.1.13", "@types/nodemailer": "^6.4.17", "@types/passport-jwt": "^4.0.1", "@types/supertest": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d88823f..3dd343a 100755 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,9 +101,9 @@ importers: handlebars: specifier: ^4.7.8 version: 4.7.8 - node-jose: - specifier: ^2.2.0 - version: 2.2.0 + nestjs-telegraf: + specifier: ^2.8.1 + version: 2.8.1(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(telegraf@4.16.3)(typescript@5.7.3) nodemailer: specifier: ^6.9.16 version: 6.9.16 @@ -122,6 +122,9 @@ importers: slugify: specifier: ^1.6.6 version: 1.6.6 + telegraf: + specifier: ^4.16.3 + version: 4.16.3 typeorm: specifier: ^0.3.20 version: 0.3.20(ioredis@5.4.2)(pg@8.13.1)(redis@4.7.0)(ts-node@10.9.2(@types/node@20.17.15)(typescript@5.7.3)) @@ -147,9 +150,6 @@ importers: '@types/node': specifier: ^20.17.14 version: 20.17.15 - '@types/node-jose': - specifier: ^1.1.13 - version: 1.1.13 '@types/nodemailer': specifier: ^6.4.17 version: 6.4.17 @@ -1415,6 +1415,9 @@ packages: '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} + '@telegraf/types@7.1.0': + resolution: {integrity: sha512-kGevOIbpMcIlCDeorKGpwZmdH7kHbqlk/Yj6dEpJMKEQw5lk0KVQY0OLXaCswy8GqlIVLd5625OB+rAntP9xVw==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -1511,9 +1514,6 @@ packages: '@types/mjml@4.7.4': resolution: {integrity: sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==} - '@types/node-jose@1.1.13': - resolution: {integrity: sha512-QjMd4yhwy1EvSToQn0YI3cD29YhyfxFwj7NecuymjLys2/P0FwxWnkgBlFxCai6Y3aBCe7rbwmqwJJawxlgcXw==} - '@types/node@20.17.15': resolution: {integrity: sha512-ymrDMpEhuYz7PXTItXhY0ZDBDZT/RgsmFM9rBiRLOSVX1HKJhhrLXuLY00fHsFsugYT1wZU3IC4dleUUC22UDQ==} @@ -1674,6 +1674,10 @@ packages: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -1900,10 +1904,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - base64url@3.0.1: - resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} - engines: {node: '>=6.0.0'} - bcrypt@5.1.1: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} @@ -1943,9 +1943,18 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-alloc-unsafe@1.1.0: + resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} + + buffer-alloc@1.2.0: + resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-fill@1.0.0: + resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2523,9 +2532,6 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2667,6 +2673,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -3752,9 +3762,6 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - long@5.3.1: - resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} - lower-case@1.1.4: resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} @@ -4002,6 +4009,10 @@ packages: mnemonist@0.39.6: resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4028,6 +4039,15 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + nestjs-telegraf@2.8.1: + resolution: {integrity: sha512-7H3r6Yl4YNnJn/YSPcP26O2ESAKLJTgjKP6XuBkKw5OrYBXguGWmeUdNHYISCZTjKegHxfq8/9bjmfMrWrGIIA==} + peerDependencies: + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + reflect-metadata: ^0.2.2 + telegraf: ^4.0.0 + typescript: ^4.1.2 || ^5.0.0 + nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} @@ -4052,10 +4072,6 @@ packages: encoding: optional: true - node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - node-gyp-build-optional-packages@5.2.2: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true @@ -4063,9 +4079,6 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-jose@2.2.0: - resolution: {integrity: sha512-XPCvJRr94SjLrSIm4pbYHKLEaOsDvJCpyFw/6V/KK/IXmyZ6SFBzAUDO9HQf4DB/nTEFcRGH87mNciOP23kFjw==} - node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -4216,6 +4229,10 @@ packages: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} + p-timeout@4.1.0: + resolution: {integrity: sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==} + engines: {node: '>=10'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -4227,9 +4244,6 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - pako@2.1.0: - resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} - param-case@2.1.1: resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} @@ -4436,10 +4450,6 @@ packages: process-warning@4.0.1: resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} @@ -4659,6 +4669,9 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-compare@1.1.4: + resolution: {integrity: sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -4680,6 +4693,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sandwich-stream@2.0.2: + resolution: {integrity: sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==} + engines: {node: '>= 0.10'} + sax@1.2.1: resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} @@ -4950,6 +4967,11 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + telegraf@4.16.3: + resolution: {integrity: sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w==} + engines: {node: ^12.20.0 || >=14.13.1} + hasBin: true + terser-webpack-plugin@5.3.11: resolution: {integrity: sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==} engines: {node: '>= 10.13.0'} @@ -7287,6 +7309,8 @@ snapshots: '@sqltools/formatter@1.2.5': {} + '@telegraf/types@7.1.0': {} + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -7405,10 +7429,6 @@ snapshots: '@types/mjml-core': 4.15.1 optional: true - '@types/node-jose@1.1.13': - dependencies: - '@types/node': 20.17.15 - '@types/node@20.17.15': dependencies: undici-types: 6.19.8 @@ -7640,6 +7660,10 @@ snapshots: abbrev@2.0.0: optional: true + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + abstract-logging@2.0.1: {} acorn-jsx@5.3.2(acorn@8.14.0): @@ -7918,8 +7942,6 @@ snapshots: base64-js@1.5.1: {} - base64url@3.0.1: {} - bcrypt@5.1.1: dependencies: '@mapbox/node-pre-gyp': 1.0.11 @@ -7969,8 +7991,17 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-alloc-unsafe@1.1.0: {} + + buffer-alloc@1.2.0: + dependencies: + buffer-alloc-unsafe: 1.1.0 + buffer-fill: 1.0.0 + buffer-equal-constant-time@1.0.1: {} + buffer-fill@1.0.0: {} + buffer-from@1.1.2: {} buffer@4.9.2: @@ -8632,8 +8663,6 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es6-promise@4.2.8: {} - escalade@3.2.0: {} escape-goat@3.0.0: @@ -8796,6 +8825,8 @@ snapshots: esutils@2.0.3: {} + event-target-shim@5.0.1: {} + eventemitter3@5.0.1: {} events@1.1.1: {} @@ -10246,8 +10277,6 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 - long@5.3.1: {} - lower-case@1.1.4: optional: true @@ -10707,6 +10736,8 @@ snapshots: dependencies: obliterator: 2.0.5 + mri@1.2.0: {} + ms@2.1.3: {} msgpackr-extract@3.0.3: @@ -10739,6 +10770,15 @@ snapshots: neo-async@2.6.2: {} + nestjs-telegraf@2.8.1(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(telegraf@4.16.3)(typescript@5.7.3): + dependencies: + '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1) + lodash: 4.17.21 + reflect-metadata: 0.2.2 + telegraf: 4.16.3 + typescript: 5.7.3 + nice-try@1.0.5: optional: true @@ -10759,8 +10799,6 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-forge@1.3.1: {} - node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.0.3 @@ -10768,18 +10806,6 @@ snapshots: node-int64@0.4.0: {} - node-jose@2.2.0: - dependencies: - base64url: 3.0.1 - buffer: 6.0.3 - es6-promise: 4.2.8 - lodash: 4.17.21 - long: 5.3.1 - node-forge: 1.3.1 - pako: 2.1.0 - process: 0.11.10 - uuid: 9.0.1 - node-releases@2.0.19: {} nodemailer@6.9.16: {} @@ -10951,6 +10977,8 @@ snapshots: p-finally: 1.0.0 optional: true + p-timeout@4.1.0: {} + p-try@2.2.0: {} p-wait-for@3.2.0: @@ -10960,8 +10988,6 @@ snapshots: package-json-from-dist@1.0.1: {} - pako@2.1.0: {} - param-case@2.1.1: dependencies: no-case: 2.3.2 @@ -11163,8 +11189,6 @@ snapshots: process-warning@4.0.1: {} - process@0.11.10: {} - promise@7.3.1: dependencies: asap: 2.0.6 @@ -11423,6 +11447,10 @@ snapshots: safe-buffer@5.2.1: {} + safe-compare@1.1.4: + dependencies: + buffer-alloc: 1.2.0 + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -11446,6 +11474,8 @@ snapshots: safer-buffer@2.1.2: {} + sandwich-stream@2.0.2: {} + sax@1.2.1: {} schema-utils@3.3.0: @@ -11740,6 +11770,20 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + telegraf@4.16.3: + dependencies: + '@telegraf/types': 7.1.0 + abort-controller: 3.0.0 + debug: 4.4.0 + mri: 1.2.0 + node-fetch: 2.7.0 + p-timeout: 4.1.0 + safe-compare: 1.1.4 + sandwich-stream: 2.0.2 + transitivePeerDependencies: + - encoding + - supports-color + terser-webpack-plugin@5.3.11(webpack@5.97.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 diff --git a/src/app.module.ts b/src/app.module.ts index 0fb46ee..9a6bf29 100755 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,11 +7,13 @@ import { ConfigModule } from "@nestjs/config"; import { ThrottlerModule } from "@nestjs/throttler"; import { TypeOrmModule } from "@nestjs/typeorm"; import { MailerModule } from "@nestjs-modules/mailer"; +import { TelegrafModule } from "nestjs-telegraf"; import { bullMqConfig } from "./configs/bullmq.config"; import { cacheConfig } from "./configs/cache.config"; import { mailerConfig } from "./configs/mailer.config"; import { rateLimitConfig } from "./configs/rateLimit.config"; +import { telegrafConfig } from "./configs/telegraf.config"; import { databaseConfigs } from "./configs/typeorm.config"; import { HTTPLogger } from "./core/middlewares/logger.middleware"; import { AddressModule } from "./modules/address/address.module"; @@ -24,6 +26,7 @@ import { DanakServicesModule } from "./modules/danak-services/danak-services.mod import { DashboardModule } from "./modules/dashboards/dashboard.module"; import { InvoicesModule } from "./modules/invoices/invoices.module"; import { LearningModule } from "./modules/learnings/learning.module"; +import { LoggerModule } from "./modules/logger/logger.module"; import { NotificationModule } from "./modules/notifications/notifications.module"; import { PaymentsModule } from "./modules/payments/payments.module"; import { SettingModule } from "./modules/settings/settings.module"; @@ -35,6 +38,7 @@ import { WalletsModule } from "./modules/wallets/wallets.module"; @Module({ imports: [ + TelegrafModule.forRootAsync(telegrafConfig()), MailerModule.forRootAsync(mailerConfig()), BullModule.forRootAsync(bullMqConfig()), ThrottlerModule.forRootAsync(rateLimitConfig()), @@ -61,6 +65,7 @@ import { WalletsModule } from "./modules/wallets/wallets.module"; AdsModule, AddressModule, DashboardModule, + LoggerModule, ], controllers: [], providers: [], diff --git a/src/configs/bullmq.config.ts b/src/configs/bullmq.config.ts index ed0021f..c11aa0f 100755 --- a/src/configs/bullmq.config.ts +++ b/src/configs/bullmq.config.ts @@ -9,10 +9,9 @@ export function bullMqConfig(): SharedBullAsyncConfiguration { url: configService.getOrThrow("REDIS_URI"), }, defaultJobOptions: { - removeOnComplete: 2000, // Consider lower values in high-volume production - removeOnFail: 5000, // Consider lower values to reduce Redis memory usage - attempts: 3, // Reasonable default, adjust based on job criticality - backoff: { type: "exponential", delay: 2000 }, // Consider adding for better retry behavior + removeOnComplete: false, + removeOnFail: false, + attempts: 5, // Reasonable default, adjust based on job criticality }, }), }; diff --git a/src/configs/telegraf.config.ts b/src/configs/telegraf.config.ts new file mode 100644 index 0000000..ac54ffc --- /dev/null +++ b/src/configs/telegraf.config.ts @@ -0,0 +1,12 @@ +import { ConfigService } from "@nestjs/config"; +import { TelegrafModuleAsyncOptions } from "nestjs-telegraf"; + +export function telegrafConfig(): TelegrafModuleAsyncOptions { + return { + inject: [ConfigService], + useFactory: async (configService: ConfigService) => ({ + token: configService.getOrThrow("TELEGRAM_BOT_TOKEN"), + botName: configService.getOrThrow("TELEGRAM_BOT_NAME"), + }), + }; +} diff --git a/src/modules/announcements/constants/index.ts b/src/modules/announcements/constants/index.ts index bfbbffd..e415fe7 100755 --- a/src/modules/announcements/constants/index.ts +++ b/src/modules/announcements/constants/index.ts @@ -5,7 +5,7 @@ export const ANNOUNCEMENT = Object.freeze({ // ANNOUNCEMENT_SEND_JOB_PRIORITY: 1, ANNOUNCEMENT_SEND_JOB_ATTEMPTS: 3, - ANNOUNCEMENT_SEND_JOB_BACKOFF: 1000, + ANNOUNCEMENT_SEND_JOB_BACKOFF: 5 * 1000, ANNOUNCEMENT_SEND_JOB_TIMEOUT: 10000, // ANNOUNCEMENT_PUBLISH_JOB_PRIORITY: 1, diff --git a/src/modules/announcements/providers/announcement.service.ts b/src/modules/announcements/providers/announcement.service.ts index f3af4cc..764c2ba 100755 --- a/src/modules/announcements/providers/announcement.service.ts +++ b/src/modules/announcements/providers/announcement.service.ts @@ -57,7 +57,7 @@ export class AnnouncementService { { delay: dayjs(announcement.publishAt).diff(dayjs(), "millisecond"), attempts: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_ATTEMPTS, - backoff: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_BACKOFF, + backoff: { type: "exponential", delay: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_BACKOFF }, }, ); diff --git a/src/modules/invoices/constants/index.ts b/src/modules/invoices/constants/index.ts index d1d6d68..4c4c4ba 100644 --- a/src/modules/invoices/constants/index.ts +++ b/src/modules/invoices/constants/index.ts @@ -3,17 +3,17 @@ export const INVOICE = Object.freeze({ INVOICE_REMINDER_JOB_NAME: "reminderInvoice", INVOICE_RECURRING_JOB_NAME: "recurringInvoice", // - INVOICE_REMINDER_JOB_PRIORITY: 1, // High priority - INVOICE_REMINDER_JOB_ATTEMPTS: 3, // Retry 3 times - INVOICE_REMINDER_JOB_BACKOFF: 1000, // Retry after 1 second - INVOICE_REMINDER_JOB_TIMEOUT: 10000, // Timeout after 10 seconds - INVOICE_REMINDER_REPEAT_DELAY: 86400000, // 1 day delay in milliseconds + INVOICE_REMINDER_JOB_PRIORITY: 1, // high priority + INVOICE_REMINDER_JOB_ATTEMPTS: 3, // 3 times + INVOICE_REMINDER_JOB_BACKOFF: 5 * 1000, // ms + INVOICE_REMINDER_JOB_TIMEOUT: 10000, // timeout after 10 seconds + INVOICE_REMINDER_REPEAT_DELAY: 1 * 24 * 60 * 60 * 1000, // 1 day delay in milliseconds // - INVOICE_RECURRING_JOB_PRIORITY: 1, // High priority - INVOICE_RECURRING_JOB_ATTEMPTS: 3, // Retry 3 times - INVOICE_RECURRING_JOB_BACKOFF: 1000, // Retry after 1 second - INVOICE_RECURRING_JOB_TIMEOUT: 10000, // Timeout after 10 seconds + INVOICE_RECURRING_JOB_PRIORITY: 1, // high priority + INVOICE_RECURRING_JOB_ATTEMPTS: 3, // retry 3 times + INVOICE_RECURRING_JOB_BACKOFF: 5 * 1000, // retry after 1 second + INVOICE_RECURRING_JOB_TIMEOUT: 10000, // timeout after 10 seconds // FINE_PERCENTAGE: 0.01, // 1% of the total price MAX_DAYS_AFTER_OVERDUE: 10, diff --git a/src/modules/invoices/invoices.module.ts b/src/modules/invoices/invoices.module.ts index c2a7e74..0fdab38 100755 --- a/src/modules/invoices/invoices.module.ts +++ b/src/modules/invoices/invoices.module.ts @@ -18,9 +18,11 @@ import { UtilsModule } from "../utils/utils.module"; import { WalletsModule } from "../wallets/wallets.module"; import { InvoiceProcessor } from "./queue/invoice.processor"; import { InvoiceItemsRepository } from "./repositories/invoice-items.repository"; +import { LoggerModule } from "../logger/logger.module"; @Module({ imports: [ + LoggerModule, BullModule.registerQueue({ name: INVOICE.INVOICE_QUEUE_NAME }), TypeOrmModule.forFeature([Invoice, InvoiceItem, Discount, UsageDiscount]), UsersModule, diff --git a/src/modules/invoices/queue/invoice.processor.ts b/src/modules/invoices/queue/invoice.processor.ts index 1ba7a86..d779374 100644 --- a/src/modules/invoices/queue/invoice.processor.ts +++ b/src/modules/invoices/queue/invoice.processor.ts @@ -1,5 +1,4 @@ import { InjectQueue, Processor } from "@nestjs/bullmq"; -import { Logger } from "@nestjs/common"; import { Job, Queue } from "bullmq"; import dayjs from "dayjs"; // eslint-disable-next-line import/no-named-as-default @@ -7,6 +6,7 @@ import Decimal from "decimal.js"; import { DataSource, QueryRunner } from "typeorm"; import { WorkerProcessor } from "../../../common/queues/worker.processor"; +import { LoggerService } from "../../logger/logger.service"; import { NotificationsService } from "../../notifications/providers/notifications.service"; import { SubscriptionStatus } from "../../subscriptions/enums/subscription-status.enum"; import { User } from "../../users/entities/user.entity"; @@ -16,21 +16,22 @@ import { Invoice } from "../entities/invoice.entity"; import { InvoiceStatus } from "../enums/invoice-status.enum"; import { InvoicesService } from "../providers/invoices.service"; -@Processor(INVOICE.INVOICE_QUEUE_NAME) +@Processor(INVOICE.INVOICE_QUEUE_NAME, { concurrency: 5 }) export class InvoiceProcessor extends WorkerProcessor { - protected readonly logger = new Logger(InvoiceProcessor.name); + // protected readonly logger = new Logger(InvoiceProcessor.name); constructor( @InjectQueue(INVOICE.INVOICE_QUEUE_NAME) private readonly invoiceQueue: Queue, private readonly invoicesService: InvoicesService, private readonly dataSource: DataSource, private readonly notificationService: NotificationsService, + protected readonly logger: LoggerService, ) { super(); } async process(job: Job, token?: string) { - this.logger.log(job, token); + this.logger.log(job); switch (job.name) { case INVOICE.INVOICE_REMINDER_JOB_NAME: return this.sendBillInvoiceReminder(job, token); @@ -234,7 +235,7 @@ export class InvoiceProcessor extends WorkerProcessor { { delay: INVOICE.INVOICE_REMINDER_REPEAT_DELAY, // 1 day delay in milliseconds attempts: INVOICE.INVOICE_REMINDER_JOB_ATTEMPTS, - backoff: INVOICE.INVOICE_REMINDER_JOB_BACKOFF, + backoff: { type: "exponential", delay: INVOICE.INVOICE_REMINDER_JOB_BACKOFF }, }, ); } @@ -261,7 +262,7 @@ export class InvoiceProcessor extends WorkerProcessor { }; await Promise.all( - admins.map((admin) => this.notificationService.createRucurringInvoiceNotification(admin.id, notificationPayload, queryRunner)), + admins.map((admin) => this.notificationService.createRecurringInvoiceNotification(admin.id, notificationPayload, queryRunner)), ); } } diff --git a/src/modules/logger/logger.module.ts b/src/modules/logger/logger.module.ts new file mode 100644 index 0000000..64ceb4d --- /dev/null +++ b/src/modules/logger/logger.module.ts @@ -0,0 +1,9 @@ +import { Module } from "@nestjs/common"; + +import { LoggerService } from "./logger.service"; + +@Module({ + providers: [LoggerService], + exports: [LoggerService], +}) +export class LoggerModule {} diff --git a/src/modules/logger/logger.service.ts b/src/modules/logger/logger.service.ts new file mode 100644 index 0000000..071303c --- /dev/null +++ b/src/modules/logger/logger.service.ts @@ -0,0 +1,43 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { InjectBot } from "nestjs-telegraf"; +import { Telegraf } from "telegraf"; + +@Injectable() +export class LoggerService extends Logger { + private chatId: string; + + constructor( + @InjectBot() private bot: Telegraf, + private configService: ConfigService, + ) { + super(); + this.chatId = this.configService.getOrThrow("TELEGRAM_CHAT_ID"); + } + + async sendLogToTelegram(level: string, message: string) { + try { + const logMessage = `🚨 *${level.toUpperCase()} Log:*\n${message}`; + await this.bot.telegram.sendMessage(this.chatId, logMessage, { + parse_mode: "Markdown", + }); + } catch (error) { + super.error(`Failed to send log to Telegram:`, error); + } + } + + override log(message: any) { + this.sendLogToTelegram("test", message); + super.log(message); + } + + override error(message: any, trace?: any) { + super.error(message, trace); + this.sendLogToTelegram("error", `${message}\nTrace: ${trace}`); + } + + override warn(message: any) { + super.warn(message); + this.sendLogToTelegram("warn", message); + } +} diff --git a/src/modules/notifications/providers/notifications.service.ts b/src/modules/notifications/providers/notifications.service.ts index 0b4b83c..c1562e4 100755 --- a/src/modules/notifications/providers/notifications.service.ts +++ b/src/modules/notifications/providers/notifications.service.ts @@ -317,7 +317,7 @@ export class NotificationsService { // //************************ */ - async createRucurringInvoiceNotification(recipientId: string, data: IInvoiceNotificationData, queryRunner: QueryRunner) { + async createRecurringInvoiceNotification(recipientId: string, data: IInvoiceNotificationData, queryRunner: QueryRunner) { const message = NotificationMessage.RECURRING_INVOICE_MESSAGE.replace("[invoiceNumber]", data.invoiceId); //sent notification based on the userSettings const { isActive } = await this.userSettingsService.getUserNotificationSettingWithType(NotifType.RECURRING_INVOICE, recipientId);