diff --git a/package.json b/package.json index ac92c29..7921080 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,13 @@ "@nestjs/mapped-types": "*", "@nestjs/microservices": "^11.1.14", "@nestjs/platform-express": "^11.0.1", + "@teacinema/contracts": "^1.1.0", "@teacinema/core": "^1.0.9", "amqp-connection-manager": "^5.0.0", "amqplib": "^0.10.9", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "zod": "^4.3.6" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 1e51397..1417b15 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,13 +1,16 @@ import { Module } from '@nestjs/common' import { ConfigModule } from '@nestjs/config' +import configuration from './config/configuration' import { RmqModule } from './infra/rmq/rmq.module' import { NotificationsModule } from './modules/notifications/notifications.module' @Module({ imports: [ ConfigModule.forRoot({ - isGlobal: true + isGlobal: true, + load: [configuration], + expandVariables: true }), RmqModule, NotificationsModule diff --git a/src/config/configuration.ts b/src/config/configuration.ts new file mode 100644 index 0000000..5d7b9ff --- /dev/null +++ b/src/config/configuration.ts @@ -0,0 +1,22 @@ +import validationSchema from './validation.schema' + +export default () => { + const parsed = validationSchema.safeParse(process.env) + + if (!parsed.success) { + console.error('Invalid enviroment variables', parsed.error.format()) + process.exit(1) + } + + const env = parsed.data + + return { + app: { + nodeEnv: env.NODE_ENV + }, + rmq: { + url: env.RMQ_URL, + queue: env.RMQ_QUEUE + } + } +} diff --git a/src/config/validation.schema.ts b/src/config/validation.schema.ts new file mode 100644 index 0000000..9c03c59 --- /dev/null +++ b/src/config/validation.schema.ts @@ -0,0 +1,13 @@ +import { z } from 'zod' + +export enum Enviroment { + Development = 'development', + Production = 'production', + Test = 'test' +} + +export default z.object({ + NODE_ENV: z.enum(Enviroment).default(Enviroment.Development), + RMQ_URL: z.string().nonempty(), + RMQ_QUEUE: z.string().nonempty() +}) diff --git a/src/main.ts b/src/main.ts index 805d98a..ef14e7a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,8 +12,8 @@ async function bootstrap() { app.connectMicroservice({ transport: Transport.RMQ, options: { - urls: [config.getOrThrow('RMQ_URL')], - queue: config.getOrThrow('RMQ_QUEUE'), + urls: [config.get('rmq.url')], + queue: config.get('rmq.queue'), queueOptions: { durable: false }, diff --git a/src/modules/notifications/notifications.controller.ts b/src/modules/notifications/notifications.controller.ts index a85d90b..3fc9980 100644 --- a/src/modules/notifications/notifications.controller.ts +++ b/src/modules/notifications/notifications.controller.ts @@ -1,5 +1,6 @@ import { Controller } from '@nestjs/common' import { Ctx, EventPattern, Payload, RmqContext } from '@nestjs/microservices' +import type { OtpRequestedEvent } from '@teacinema/contracts' import { RmqService } from '../../infra/rmq/rmq.service' @@ -13,7 +14,10 @@ export class NotificationsController { ) {} @EventPattern('auth.otp.requested') - public otpRequested(@Payload() data: any, @Ctx() ctx: RmqContext) { + public otpRequested( + @Payload() data: OtpRequestedEvent, + @Ctx() ctx: RmqContext + ) { try { console.log('OTP received', data) this.rmqService.ack(ctx) diff --git a/yarn.lock b/yarn.lock index 0568f28..49c41f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -333,6 +333,11 @@ resolved "https://registry.yarnpkg.com/@borewit/text-codec/-/text-codec-0.2.1.tgz#5d171538907a8cb395fdc2eb5e8f7947d96c7f2f" integrity sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw== +"@bufbuild/protobuf@^2.0.0", "@bufbuild/protobuf@^2.10.2": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-2.11.0.tgz#3ec3985c9074b23aea337957225fe15a0e845f8e" + integrity sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ== + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -992,7 +997,7 @@ resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz#b9b536b7c3571567aa1d0223db8baa1a51505a19" integrity sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw== -"@nestjs/microservices@^11.1.14": +"@nestjs/microservices@^11.1.12", "@nestjs/microservices@^11.1.14": version "11.1.14" resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-11.1.14.tgz#8fa2de758ec2c768da7d993d79f772b699a507ff" integrity sha512-7x+QaX7351xJMYpjw4pqwoACXtSxuUQt4Prb7ZyqqsCawnBRrObPpZ/HIdpdKJPgo8vFfLJoAnkFJ+mQ6xz6Rw== @@ -1077,6 +1082,16 @@ dependencies: "@sinonjs/commons" "^3.0.1" +"@teacinema/contracts@^1.1.0": + version "1.1.0" + resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.1.0/contracts-1.1.0.tgz#0d2f03f283dc9ee048eeb770152127f2037b7133" + integrity sha512-x90R4R96AgrUDzOjUT7ePtc7phG3Gx61sI8/CZ1hETF3Ok/TWTHblxX/CIZVcOormBrxEh1FfU39P8/nfno91g== + dependencies: + "@nestjs/microservices" "^11.1.12" + protoc "33.4.0" + rxjs "^7.8.2" + ts-proto "2.11.0" + "@teacinema/core@^1.0.9": version "1.0.9" resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcore/-/1.0.9/core-1.0.9.tgz#deec0675c6cc03fe2511a6b8dc5d6b6763998708" @@ -2081,6 +2096,11 @@ caniuse-lite@^1.0.30001759: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz#0e576b6f374063abcd499d202b9ba1301be29b70" integrity sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA== +case-anything@^2.1.13: + version "2.1.13" + resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.13.tgz#0cdc16278cb29a7fcdeb072400da3f342ba329e9" + integrity sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng== + chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -2340,6 +2360,11 @@ depd@^2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-newline@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -2375,6 +2400,13 @@ dotenv@^16.4.5: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== +dprint-node@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/dprint-node/-/dprint-node-1.0.8.tgz#a02470722d8208a7d7eb3704328afda1d6758625" + integrity sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg== + dependencies: + detect-libc "^1.0.3" + dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" @@ -4196,6 +4228,11 @@ promise-breaker@^6.0.0: resolved "https://registry.yarnpkg.com/promise-breaker/-/promise-breaker-6.0.0.tgz#107d2b70f161236abdb4ac5a736c7eb8df489d0f" integrity sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA== +protoc@33.4.0: + version "33.4.0" + resolved "https://registry.yarnpkg.com/protoc/-/protoc-33.4.0.tgz#4a288b59f5f50b9a2c4bbf345276357e59dd6f10" + integrity sha512-dC1SJKbn4f60onsAMrfiPMygfSz4w/tPGHtPCqMSa5CLfHocJXkHjsvXeuuhjSPAJ8uUc8rfUvs0Hy9nmKIOhA== + proxy-addr@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -4330,7 +4367,7 @@ rxjs@7.8.1: dependencies: tslib "^2.1.0" -rxjs@^7.8.1: +rxjs@^7.8.1, rxjs@^7.8.2: version "7.8.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== @@ -4794,6 +4831,30 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +ts-poet@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-6.12.0.tgz#f28eb91778fdff8e1b264600c7ddddb40cd39d84" + integrity sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA== + dependencies: + dprint-node "^1.0.8" + +ts-proto-descriptors@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz#0c60525ea94748f7b3f394dc10d6eb8eeac4fe39" + integrity sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA== + dependencies: + "@bufbuild/protobuf" "^2.0.0" + +ts-proto@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-2.11.0.tgz#4b24b3a39893441d97e8a875e7d7c509a7bb4521" + integrity sha512-Emqt0T/Wf74aT+IAoOqEkWWhxVOVF6QwVW4CBIyL3RRQORJpaQDVHy/Ykg9psQH/Zo6XMpT9KBRjpkVSZ0vXkQ== + dependencies: + "@bufbuild/protobuf" "^2.10.2" + case-anything "^2.1.13" + ts-poet "^6.12.0" + ts-proto-descriptors "2.1.0" + tsconfig-paths-webpack-plugin@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz#f7459a8ed1dd4cf66ad787aefc3d37fff3cf07fc" @@ -5164,3 +5225,8 @@ yoctocolors-cjs@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw== + +zod@^4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.6.tgz#89c56e0aa7d2b05107d894412227087885ab112a" + integrity sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==