create-easy-stack 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create.mjs +244 -0
- package/infra/email/files/src/core/config/email.env.ts +73 -0
- package/infra/email/files/src/core/infrastructure/email/email-dispatcher.port.ts +13 -0
- package/infra/email/files/src/core/infrastructure/email/email-layout.spec.ts +83 -0
- package/infra/email/files/src/core/infrastructure/email/email-layout.ts +88 -0
- package/infra/email/files/src/core/infrastructure/email/email-sender.factory.spec.ts +87 -0
- package/infra/email/files/src/core/infrastructure/email/email-sender.factory.ts +35 -0
- package/infra/email/files/src/core/infrastructure/email/email-sender.port.ts +19 -0
- package/infra/email/files/src/core/infrastructure/email/email.job.spec.ts +101 -0
- package/infra/email/files/src/core/infrastructure/email/email.job.ts +64 -0
- package/infra/email/files/src/core/infrastructure/email/email.module.spec.ts +60 -0
- package/infra/email/files/src/core/infrastructure/email/email.module.ts +34 -0
- package/infra/email/files/src/core/infrastructure/email/log-email-sender.spec.ts +34 -0
- package/infra/email/files/src/core/infrastructure/email/log-email-sender.ts +17 -0
- package/infra/email/files/src/core/infrastructure/email/smtp-email-sender.spec.ts +99 -0
- package/infra/email/files/src/core/infrastructure/email/smtp-email-sender.ts +63 -0
- package/infra/email/infra.json +58 -0
- package/infra/prisma-postgres/docker.service.yml +12 -0
- package/infra/prisma-postgres/files/prisma/schema.prisma +10 -0
- package/infra/prisma-postgres/files/prisma.config.mjs +10 -0
- package/infra/prisma-postgres/files/src/core/config/database.env.ts +13 -0
- package/infra/prisma-postgres/files/src/core/infrastructure/database/database.module.ts +9 -0
- package/infra/prisma-postgres/files/src/core/infrastructure/database/prisma.service.ts +26 -0
- package/infra/prisma-postgres/infra.json +60 -0
- package/infra/rabbitmq/docker.service.yml +16 -0
- package/infra/rabbitmq/files/src/core/config/messaging.env.ts +29 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/inline-job-queue.spec.ts +60 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/inline-job-queue.ts +33 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-failure.spec.ts +23 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-failure.ts +19 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-payload-cipher.spec.ts +80 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-payload-cipher.ts +66 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-queue.boundary.spec.ts +34 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-queue.factory.ts +21 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-queue.module.spec.ts +75 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-queue.module.ts +30 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/job-queue.port.ts +59 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/rabbitmq-job-queue.spec.ts +510 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/jobs/rabbitmq-job-queue.ts +353 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/rabbitmq/rabbitmq.module.ts +9 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/rabbitmq/rabbitmq.service.spec.ts +289 -0
- package/infra/rabbitmq/files/src/core/infrastructure/messaging/rabbitmq/rabbitmq.service.ts +207 -0
- package/infra/rabbitmq/infra.json +55 -0
- package/infra/redis/docker.service.yml +10 -0
- package/infra/redis/files/src/core/http/decorators/rate-limit.decorator.ts +26 -0
- package/infra/redis/files/src/core/http/interceptors/rate-limit.interceptor.spec.ts +180 -0
- package/infra/redis/files/src/core/http/interceptors/rate-limit.interceptor.ts +105 -0
- package/infra/redis/files/src/core/infrastructure/redis/cache.constants.ts +67 -0
- package/infra/redis/files/src/core/infrastructure/redis/idempotency/idempotency.module.ts +9 -0
- package/infra/redis/files/src/core/infrastructure/redis/idempotency/idempotency.service.spec.ts +146 -0
- package/infra/redis/files/src/core/infrastructure/redis/idempotency/idempotency.service.ts +131 -0
- package/infra/redis/files/src/core/infrastructure/redis/lock/lock.module.ts +9 -0
- package/infra/redis/files/src/core/infrastructure/redis/lock/lock.service.integration-spec.ts +111 -0
- package/infra/redis/files/src/core/infrastructure/redis/lock/lock.service.ts +82 -0
- package/infra/redis/files/src/core/infrastructure/redis/rate-limit/rate-limit.module.ts +15 -0
- package/infra/redis/files/src/core/infrastructure/redis/rate-limit/rate-limit.service.spec.ts +45 -0
- package/infra/redis/files/src/core/infrastructure/redis/rate-limit/rate-limit.service.ts +38 -0
- package/infra/redis/files/src/core/infrastructure/redis/redis.module.ts +9 -0
- package/infra/redis/files/src/core/infrastructure/redis/redis.service.ts +196 -0
- package/infra/redis/infra.json +53 -0
- package/infra/storage-cloudinary/files/src/core/config/storage.env.ts +43 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/cloudinary-image-storage.spec.ts +275 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/cloudinary-image-storage.ts +158 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/image-storage.factory.ts +30 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/image-storage.module.ts +17 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/image-storage.port.ts +38 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/image-type.spec.ts +48 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/image-type.ts +25 -0
- package/infra/storage-cloudinary/files/src/core/infrastructure/storage/unconfigured-image-storage.ts +19 -0
- package/infra/storage-cloudinary/infra.json +73 -0
- package/lib/fs-utils.mjs +115 -0
- package/lib/registry.mjs +50 -0
- package/lib/scaffold.mjs +157 -0
- package/package.json +37 -0
- package/templates/nest-ddd/files/.env.example +5 -0
- package/templates/nest-ddd/files/.husky/commit-msg +1 -0
- package/templates/nest-ddd/files/.husky/pre-commit +1 -0
- package/templates/nest-ddd/files/.oxlintrc.json +10 -0
- package/templates/nest-ddd/files/.prettierrc +4 -0
- package/templates/nest-ddd/files/_gitignore +40 -0
- package/templates/nest-ddd/files/commitlint.config.js +3 -0
- package/templates/nest-ddd/files/nest-cli.json +8 -0
- package/templates/nest-ddd/files/package.json +66 -0
- package/templates/nest-ddd/files/plop-templates/command/command.ts.hbs +5 -0
- package/templates/nest-ddd/files/plop-templates/command/handler.ts.hbs +30 -0
- package/templates/nest-ddd/files/plop-templates/module/application/commands/create-{{kebab}}.command.ts.hbs +5 -0
- package/templates/nest-ddd/files/plop-templates/module/application/commands/create-{{kebab}}.handler.spec.ts.hbs +35 -0
- package/templates/nest-ddd/files/plop-templates/module/application/commands/create-{{kebab}}.handler.ts.hbs +25 -0
- package/templates/nest-ddd/files/plop-templates/module/application/index.ts.hbs +5 -0
- package/templates/nest-ddd/files/plop-templates/module/application/queries/get-{{kebab}}-by-id.handler.ts.hbs +29 -0
- package/templates/nest-ddd/files/plop-templates/module/application/queries/get-{{kebab}}-by-id.query.ts.hbs +5 -0
- package/templates/nest-ddd/files/plop-templates/module/domain/entities/{{kebab}}.entity.ts.hbs +37 -0
- package/templates/nest-ddd/files/plop-templates/module/domain/events/{{kebab}}-created.event.ts.hbs +10 -0
- package/templates/nest-ddd/files/plop-templates/module/domain/exceptions/{{kebab}}.exception.ts.hbs +11 -0
- package/templates/nest-ddd/files/plop-templates/module/domain/index.ts.hbs +4 -0
- package/templates/nest-ddd/files/plop-templates/module/domain/repositories/{{kebab}}.repository.ts.hbs +7 -0
- package/templates/nest-ddd/files/plop-templates/module/presentation/controllers/{{kebab}}.controller.ts.hbs +53 -0
- package/templates/nest-ddd/files/plop-templates/module/presentation/dtos/create-{{kebab}}.dto.ts.hbs +10 -0
- package/templates/nest-ddd/files/plop-templates/module/presentation/dtos/{{kebab}}-response.dto.ts.hbs +15 -0
- package/templates/nest-ddd/files/plop-templates/module/presentation/index.ts.hbs +4 -0
- package/templates/nest-ddd/files/plop-templates/module/presentation/mappers/{{kebab}}.mapper.ts.hbs +13 -0
- package/templates/nest-ddd/files/plop-templates/module/{{kebab}}.module.ts.hbs +40 -0
- package/templates/nest-ddd/files/plop-templates/persistence-memory/infrastructure/database/repositories/in-memory-{{kebab}}.repository.ts.hbs +17 -0
- package/templates/nest-ddd/files/plop-templates/persistence-memory/infrastructure/index.ts.hbs +1 -0
- package/templates/nest-ddd/files/plop-templates/persistence-prisma/infrastructure/database/mappers/{{kebab}}.mapper.ts.hbs +29 -0
- package/templates/nest-ddd/files/plop-templates/persistence-prisma/infrastructure/database/repositories/prisma-{{kebab}}.repository.ts.hbs +28 -0
- package/templates/nest-ddd/files/plop-templates/persistence-prisma/infrastructure/index.ts.hbs +2 -0
- package/templates/nest-ddd/files/plop-templates/query/handler.ts.hbs +28 -0
- package/templates/nest-ddd/files/plop-templates/query/query.ts.hbs +5 -0
- package/templates/nest-ddd/files/plop-templates/snippets/error-codes.hbs +14 -0
- package/templates/nest-ddd/files/plop-templates/snippets/prisma-model.hbs +7 -0
- package/templates/nest-ddd/files/plopfile.mjs +186 -0
- package/templates/nest-ddd/files/src/app.controller.ts +13 -0
- package/templates/nest-ddd/files/src/app.module.ts +26 -0
- package/templates/nest-ddd/files/src/core/config/app.config.ts +9 -0
- package/templates/nest-ddd/files/src/core/config/env.validation.ts +30 -0
- package/templates/nest-ddd/files/src/core/domain/base/aggregate-root.base.ts +18 -0
- package/templates/nest-ddd/files/src/core/domain/base/domain-event.base.ts +7 -0
- package/templates/nest-ddd/files/src/core/domain/base/entity.base.ts +36 -0
- package/templates/nest-ddd/files/src/core/domain/base/value-object.base.ts +17 -0
- package/templates/nest-ddd/files/src/core/domain/exceptions/domain.exception.ts +16 -0
- package/templates/nest-ddd/files/src/core/domain/exceptions/error-codes.ts +28 -0
- package/templates/nest-ddd/files/src/core/domain/types/pagination.ts +9 -0
- package/templates/nest-ddd/files/src/core/http/decorators/client-info.decorator.ts +24 -0
- package/templates/nest-ddd/files/src/core/http/decorators/current-user.decorator.ts +19 -0
- package/templates/nest-ddd/files/src/core/http/dtos/paginated-response.dto.ts +29 -0
- package/templates/nest-ddd/files/src/core/http/dtos/pagination-query.dto.ts +17 -0
- package/templates/nest-ddd/files/src/core/http/filters/all-exceptions.filter.spec.ts +163 -0
- package/templates/nest-ddd/files/src/core/http/filters/all-exceptions.filter.ts +97 -0
- package/templates/nest-ddd/files/src/core/http/guards/max-body-size.guard.spec.ts +47 -0
- package/templates/nest-ddd/files/src/core/http/guards/max-body-size.guard.ts +31 -0
- package/templates/nest-ddd/files/src/core/http/interceptors/logging.interceptor.ts +37 -0
- package/templates/nest-ddd/files/src/core/http/interceptors/response.interceptor.ts +53 -0
- package/templates/nest-ddd/files/src/core/http/logging/app.logger.ts +34 -0
- package/templates/nest-ddd/files/src/core/index.ts +33 -0
- package/templates/nest-ddd/files/src/core/utils/correlation-id.util.spec.ts +29 -0
- package/templates/nest-ddd/files/src/core/utils/correlation-id.util.ts +15 -0
- package/templates/nest-ddd/files/src/core/utils/hash.util.spec.ts +61 -0
- package/templates/nest-ddd/files/src/core/utils/hash.util.ts +47 -0
- package/templates/nest-ddd/files/src/core/utils/snowflake.util.spec.ts +40 -0
- package/templates/nest-ddd/files/src/core/utils/snowflake.util.ts +99 -0
- package/templates/nest-ddd/files/src/core/utils/string.util.spec.ts +20 -0
- package/templates/nest-ddd/files/src/core/utils/string.util.ts +21 -0
- package/templates/nest-ddd/files/src/core/utils/time.util.spec.ts +25 -0
- package/templates/nest-ddd/files/src/core/utils/time.util.ts +25 -0
- package/templates/nest-ddd/files/src/core/utils/ttl.util.ts +22 -0
- package/templates/nest-ddd/files/src/main.ts +61 -0
- package/templates/nest-ddd/files/test/setup.ts +6 -0
- package/templates/nest-ddd/files/tsconfig.build.json +9 -0
- package/templates/nest-ddd/files/tsconfig.json +28 -0
- package/templates/nest-ddd/files/vitest.config.e2e.ts +15 -0
- package/templates/nest-ddd/files/vitest.config.ts +16 -0
- package/templates/nest-ddd/template.json +8 -0
- package/templates/node-express/files/.env.example +28 -0
- package/templates/node-express/files/docker-compose.yml +52 -0
- package/templates/node-express/files/package-lock.json +11880 -0
- package/templates/node-express/files/package.json +43 -0
- package/templates/node-express/files/server.js +13 -0
- package/templates/node-express/files/src/app.js +72 -0
- package/templates/node-express/files/src/auth/authUtils.js +116 -0
- package/templates/node-express/files/src/auth/checkAuth.js +61 -0
- package/templates/node-express/files/src/bucket_pattern/comment.model.js +27 -0
- package/templates/node-express/files/src/bucket_pattern/comment.service.js +50 -0
- package/templates/node-express/files/src/config/config.aws-s3.js +28 -0
- package/templates/node-express/files/src/config/config.cloudinary.js +13 -0
- package/templates/node-express/files/src/config/config.mongodb.js +25 -0
- package/templates/node-express/files/src/config/config.multer.js +25 -0
- package/templates/node-express/files/src/config/config.nodemailer.js +16 -0
- package/templates/node-express/files/src/controllers/access.controller.js +49 -0
- package/templates/node-express/files/src/controllers/cart.controller.js +38 -0
- package/templates/node-express/files/src/controllers/checkout.controller.js +15 -0
- package/templates/node-express/files/src/controllers/comment.controller.js +29 -0
- package/templates/node-express/files/src/controllers/discount.controller.js +68 -0
- package/templates/node-express/files/src/controllers/email.controller.js +16 -0
- package/templates/node-express/files/src/controllers/inventory.controller.js +15 -0
- package/templates/node-express/files/src/controllers/notification.controller.js +15 -0
- package/templates/node-express/files/src/controllers/product.controller.js +175 -0
- package/templates/node-express/files/src/controllers/profile.controller.js +65 -0
- package/templates/node-express/files/src/controllers/rbac.controller.js +41 -0
- package/templates/node-express/files/src/controllers/template.controller.js +20 -0
- package/templates/node-express/files/src/controllers/upload.controller.js +56 -0
- package/templates/node-express/files/src/controllers/user.controller.js +36 -0
- package/templates/node-express/files/src/core/error.response.js +84 -0
- package/templates/node-express/files/src/core/success.response.js +44 -0
- package/templates/node-express/files/src/database/init.mongodb.level0.js +16 -0
- package/templates/node-express/files/src/database/init.mongodb.level1.js +36 -0
- package/templates/node-express/files/src/database/init.redis.js +119 -0
- package/templates/node-express/files/src/helpers/asyncHandler.js +7 -0
- package/templates/node-express/files/src/helpers/check.connect.js +29 -0
- package/templates/node-express/files/src/keys/private_key.pem +28 -0
- package/templates/node-express/files/src/keys/public_key.pem +9 -0
- package/templates/node-express/files/src/logger/discord.log.js +26 -0
- package/templates/node-express/files/src/logger/discord.log.v2.js +56 -0
- package/templates/node-express/files/src/logger/mylogger.log.js +130 -0
- package/templates/node-express/files/src/logger/winston.log.js +27 -0
- package/templates/node-express/files/src/middlewares/index.js +21 -0
- package/templates/node-express/files/src/middlewares/rbac.js +37 -0
- package/templates/node-express/files/src/middlewares/role.middleware.js +12 -0
- package/templates/node-express/files/src/models/KeyToken.model.js +37 -0
- package/templates/node-express/files/src/models/apiKey.model.js +31 -0
- package/templates/node-express/files/src/models/cart.model.js +47 -0
- package/templates/node-express/files/src/models/comment.model.js +43 -0
- package/templates/node-express/files/src/models/discount.model.js +92 -0
- package/templates/node-express/files/src/models/inventory.model.js +42 -0
- package/templates/node-express/files/src/models/notification.model.js +52 -0
- package/templates/node-express/files/src/models/order.model.js +68 -0
- package/templates/node-express/files/src/models/otp.model.js +32 -0
- package/templates/node-express/files/src/models/product.model.js +144 -0
- package/templates/node-express/files/src/models/repository/cart.repo.js +71 -0
- package/templates/node-express/files/src/models/repository/discount.repo.js +63 -0
- package/templates/node-express/files/src/models/repository/inventory.repo.js +45 -0
- package/templates/node-express/files/src/models/repository/product.repo.js +145 -0
- package/templates/node-express/files/src/models/repository/shop.repo.js +18 -0
- package/templates/node-express/files/src/models/repository/spu.repo.js +18 -0
- package/templates/node-express/files/src/models/repository/user.repo.js +20 -0
- package/templates/node-express/files/src/models/resource.model.js +32 -0
- package/templates/node-express/files/src/models/role.model.js +57 -0
- package/templates/node-express/files/src/models/shop.model.js +43 -0
- package/templates/node-express/files/src/models/sku.model.js +81 -0
- package/templates/node-express/files/src/models/spu.model.js +101 -0
- package/templates/node-express/files/src/models/template.model.js +25 -0
- package/templates/node-express/files/src/models/user.model.js +82 -0
- package/templates/node-express/files/src/postman/access.post.http +22 -0
- package/templates/node-express/files/src/routes/access/index.route.js +21 -0
- package/templates/node-express/files/src/routes/cart/index.route.js +20 -0
- package/templates/node-express/files/src/routes/checkout/index.route.js +10 -0
- package/templates/node-express/files/src/routes/comment/index.route.js +16 -0
- package/templates/node-express/files/src/routes/discount/index.route.js +26 -0
- package/templates/node-express/files/src/routes/index.route.js +27 -0
- package/templates/node-express/files/src/routes/inventory/index.route.js +11 -0
- package/templates/node-express/files/src/routes/notification/index.route.js +14 -0
- package/templates/node-express/files/src/routes/product/index.route.js +38 -0
- package/templates/node-express/files/src/routes/profile/index.route.js +15 -0
- package/templates/node-express/files/src/routes/rbac/index.route.js +21 -0
- package/templates/node-express/files/src/routes/template/index.route.js +11 -0
- package/templates/node-express/files/src/routes/upload/index.route.js +28 -0
- package/templates/node-express/files/src/routes/user/index.route.js +13 -0
- package/templates/node-express/files/src/services/access.service.js +257 -0
- package/templates/node-express/files/src/services/apiKey.service.js +15 -0
- package/templates/node-express/files/src/services/cart.service.js +115 -0
- package/templates/node-express/files/src/services/checkout.service.js +218 -0
- package/templates/node-express/files/src/services/comment.service.js +185 -0
- package/templates/node-express/files/src/services/discount.service.js +282 -0
- package/templates/node-express/files/src/services/email.service.js +71 -0
- package/templates/node-express/files/src/services/inventory.service.js +35 -0
- package/templates/node-express/files/src/services/keyToken.service.js +77 -0
- package/templates/node-express/files/src/services/notification.service.js +58 -0
- package/templates/node-express/files/src/services/otp.service.js +36 -0
- package/templates/node-express/files/src/services/product.service.js +228 -0
- package/templates/node-express/files/src/services/rbac.service.js +143 -0
- package/templates/node-express/files/src/services/redis.service.js +57 -0
- package/templates/node-express/files/src/services/redisPubSub.service.js +72 -0
- package/templates/node-express/files/src/services/shop.service.js +21 -0
- package/templates/node-express/files/src/services/sku.service.js +52 -0
- package/templates/node-express/files/src/services/spu.service.js +89 -0
- package/templates/node-express/files/src/services/template.service.js +41 -0
- package/templates/node-express/files/src/services/upload.s3.service.js +55 -0
- package/templates/node-express/files/src/services/upload.service.js +74 -0
- package/templates/node-express/files/src/services/user.service.js +92 -0
- package/templates/node-express/files/src/temp/1734420604996-ci-cd.png +0 -0
- package/templates/node-express/files/src/temp/1734421222213-cover-fb.jpg +0 -0
- package/templates/node-express/files/src/temp/1734421222214-cover-fb-01.jpg +0 -0
- package/templates/node-express/files/src/temp/1734421293437-cover-fb-01.jpg +0 -0
- package/templates/node-express/files/src/temp/1734421293437-cover-fb.jpg +0 -0
- package/templates/node-express/files/src/tests/inventory.test.js +21 -0
- package/templates/node-express/files/src/tests/message_queue/kafka/consumer.js +23 -0
- package/templates/node-express/files/src/tests/message_queue/kafka/producer.js +21 -0
- package/templates/node-express/files/src/tests/message_queue/rabbitMQ/consumer.js +28 -0
- package/templates/node-express/files/src/tests/message_queue/rabbitMQ/ordered.consumer.js +26 -0
- package/templates/node-express/files/src/tests/message_queue/rabbitMQ/ordered.producer.js +31 -0
- package/templates/node-express/files/src/tests/message_queue/rabbitMQ/producer.js +26 -0
- package/templates/node-express/files/src/tests/message_queue/rabbitMQ/producerDLX.js +44 -0
- package/templates/node-express/files/src/tests/mysql/connect.js +59 -0
- package/templates/node-express/files/src/tests/product.test.js +14 -0
- package/templates/node-express/files/src/utils/index.js +78 -0
- package/templates/node-express/files/src/utils/reasonPhrases.js +344 -0
- package/templates/node-express/files/src/utils/statusCodes.js +344 -0
- package/templates/node-express/files/src/utils/template.html.js +38 -0
- package/templates/node-express/template.json +11 -0
- package/templates/react-fsd/files/index.html +13 -0
- package/templates/react-fsd/files/package.json +15 -0
- package/templates/react-fsd/files/public/favicon.svg +1 -0
- package/templates/react-fsd/files/public/icons.svg +24 -0
- package/templates/react-fsd/files/src/assets/hero.png +0 -0
- package/templates/react-fsd/files/src/assets/typescript.svg +1 -0
- package/templates/react-fsd/files/src/assets/vite.svg +1 -0
- package/templates/react-fsd/files/src/counter.ts +9 -0
- package/templates/react-fsd/files/src/main.ts +60 -0
- package/templates/react-fsd/files/src/style.css +296 -0
- package/templates/react-fsd/files/tsconfig.json +24 -0
- package/templates/react-fsd/template.json +11 -0
- package/templates/react-monolithic/files/index.html +13 -0
- package/templates/react-monolithic/files/package.json +15 -0
- package/templates/react-monolithic/files/public/favicon.svg +1 -0
- package/templates/react-monolithic/files/public/icons.svg +24 -0
- package/templates/react-monolithic/files/src/assets/hero.png +0 -0
- package/templates/react-monolithic/files/src/assets/typescript.svg +1 -0
- package/templates/react-monolithic/files/src/assets/vite.svg +1 -0
- package/templates/react-monolithic/files/src/counter.ts +9 -0
- package/templates/react-monolithic/files/src/main.ts +60 -0
- package/templates/react-monolithic/files/src/style.css +296 -0
- package/templates/react-monolithic/files/tsconfig.json +24 -0
- package/templates/react-monolithic/template.json +11 -0
- package/templates/vue-fsd/files/index.html +13 -0
- package/templates/vue-fsd/files/package.json +15 -0
- package/templates/vue-fsd/files/public/favicon.svg +1 -0
- package/templates/vue-fsd/files/public/icons.svg +24 -0
- package/templates/vue-fsd/files/src/assets/hero.png +0 -0
- package/templates/vue-fsd/files/src/assets/typescript.svg +1 -0
- package/templates/vue-fsd/files/src/assets/vite.svg +1 -0
- package/templates/vue-fsd/files/src/counter.ts +9 -0
- package/templates/vue-fsd/files/src/main.ts +60 -0
- package/templates/vue-fsd/files/src/style.css +296 -0
- package/templates/vue-fsd/files/tsconfig.json +24 -0
- package/templates/vue-fsd/template.json +11 -0
- package/templates/vue-monolithic/files/index.html +13 -0
- package/templates/vue-monolithic/files/package.json +15 -0
- package/templates/vue-monolithic/files/public/favicon.svg +1 -0
- package/templates/vue-monolithic/files/public/icons.svg +24 -0
- package/templates/vue-monolithic/files/src/assets/hero.png +0 -0
- package/templates/vue-monolithic/files/src/assets/typescript.svg +1 -0
- package/templates/vue-monolithic/files/src/assets/vite.svg +1 -0
- package/templates/vue-monolithic/files/src/counter.ts +9 -0
- package/templates/vue-monolithic/files/src/main.ts +60 -0
- package/templates/vue-monolithic/files/src/style.css +296 -0
- package/templates/vue-monolithic/files/tsconfig.json +24 -0
- package/templates/vue-monolithic/template.json +11 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const redis = require("redis");
|
|
2
|
+
|
|
3
|
+
class RedisPubSubService {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.subscriber = redis.createClient();
|
|
6
|
+
this.publisher = redis.createClient();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async connectClients() {
|
|
10
|
+
try {
|
|
11
|
+
if (!this.publisher.isOpen) {
|
|
12
|
+
console.log(">>> connect publisher");
|
|
13
|
+
await this.publisher.connect();
|
|
14
|
+
}
|
|
15
|
+
if (!this.subscriber.isOpen) {
|
|
16
|
+
console.log(">>> connect subscriber");
|
|
17
|
+
await this.subscriber.connect();
|
|
18
|
+
}
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.log("Error connecting to Redis:", error);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async publish(channel, message) {
|
|
26
|
+
await this.connectClients(); // Ensure the clients are connected
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
this.publisher.publish(channel, message, (err, reply) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
console.log("Error in publish:", err);
|
|
31
|
+
reject(err);
|
|
32
|
+
} else {
|
|
33
|
+
resolve(reply);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async subscribe(channel, callback) {
|
|
40
|
+
await this.connectClients(); // Ensure the clients are connected
|
|
41
|
+
console.log(`Subscribing to channel: ${channel}`);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// Subscribe to the channel
|
|
45
|
+
await this.subscriber.subscribe(channel, (message) => {
|
|
46
|
+
console.log(`Message received on channel ${channel}: ${message}`);
|
|
47
|
+
if (typeof callback === "function") {
|
|
48
|
+
callback(channel, message);
|
|
49
|
+
} else {
|
|
50
|
+
console.error("Provided callback is not a function.");
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(`Successfully subscribed to channel: ${channel}`);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error("Error subscribing to channel:", err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Add a method for cleanup/disconnection if needed
|
|
61
|
+
async disconnect() {
|
|
62
|
+
try {
|
|
63
|
+
await this.publisher.quit();
|
|
64
|
+
await this.subscriber.quit();
|
|
65
|
+
console.log("Redis clients disconnected.");
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.log("Error disconnecting Redis clients:", error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = new RedisPubSubService();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const shopModel = require("../models/shop.model");
|
|
4
|
+
|
|
5
|
+
const findByEmail = async ({
|
|
6
|
+
email,
|
|
7
|
+
select = {
|
|
8
|
+
email: 1,
|
|
9
|
+
password: 1,
|
|
10
|
+
name: 1,
|
|
11
|
+
status: 1,
|
|
12
|
+
roles: 1,
|
|
13
|
+
},
|
|
14
|
+
}) => {
|
|
15
|
+
console.log(">>> email: ", email);
|
|
16
|
+
return await shopModel.findOne({ email: email }).select(select).lean();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
findByEmail,
|
|
21
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { SKU } = require("../models/sku.model");
|
|
4
|
+
const { randomSpuId } = require("../utils");
|
|
5
|
+
|
|
6
|
+
class SKUService {
|
|
7
|
+
static createNewSku = async ({ spu_id, sku_list }) => {
|
|
8
|
+
try {
|
|
9
|
+
const convertSkuList = sku_list.map((sku) => ({
|
|
10
|
+
...sku,
|
|
11
|
+
spu_id,
|
|
12
|
+
sku_id: `${spu_id}_${randomSpuId()}`,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const newSkuList = await SKU.insertMany(convertSkuList);
|
|
16
|
+
|
|
17
|
+
return newSkuList;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
throw new Error(error);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
static getDetailSku = async ({ sku_id, spu_id }) => {
|
|
24
|
+
try {
|
|
25
|
+
// read cache
|
|
26
|
+
// cache miss
|
|
27
|
+
const foundSku = await SKU.findOne({ sku_id, spu_id }).lean().exec();
|
|
28
|
+
if (foundSku) {
|
|
29
|
+
// set cache here
|
|
30
|
+
}
|
|
31
|
+
return foundSku;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new Error(error);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
static getListSkuBySpuId = async ({ spu_id }) => {
|
|
38
|
+
try {
|
|
39
|
+
// read cache
|
|
40
|
+
// cache miss
|
|
41
|
+
const foundSkuList = await SKU.find({ spu_id }).lean().exec();
|
|
42
|
+
if (foundSkuList) {
|
|
43
|
+
// set cache here
|
|
44
|
+
}
|
|
45
|
+
return foundSkuList;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(error);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = SKUService;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { SPU } = require("../models/spu.model");
|
|
4
|
+
const {
|
|
5
|
+
NotFoundError,
|
|
6
|
+
ConflictRequestError,
|
|
7
|
+
} = require("../core/error.response");
|
|
8
|
+
const { findShopById } = require("../models/repository/shop.repo");
|
|
9
|
+
const { findSpuById } = require("../models/repository/spu.repo");
|
|
10
|
+
const { randomSpuId } = require("../utils");
|
|
11
|
+
const SKUService = require("./sku.service");
|
|
12
|
+
const _ = require("lodash");
|
|
13
|
+
class SPUService {
|
|
14
|
+
static createNewSpu = async ({
|
|
15
|
+
spu_name,
|
|
16
|
+
spu_slug,
|
|
17
|
+
spu_description,
|
|
18
|
+
spu_images,
|
|
19
|
+
spu_category,
|
|
20
|
+
spu_price,
|
|
21
|
+
spu_shop,
|
|
22
|
+
spu_attributes,
|
|
23
|
+
spu_ratingsAverage,
|
|
24
|
+
spu_variations,
|
|
25
|
+
spu_quantity,
|
|
26
|
+
sku_list = [],
|
|
27
|
+
}) => {
|
|
28
|
+
try {
|
|
29
|
+
// check if shop exists
|
|
30
|
+
const foundShop = await findShopById({ shop_id: spu_shop });
|
|
31
|
+
if (!foundShop) {
|
|
32
|
+
throw NotFoundError("Shop not found");
|
|
33
|
+
}
|
|
34
|
+
// check if spu_id is already exists
|
|
35
|
+
const foundSpu = await findSpuById({ spu_id });
|
|
36
|
+
if (foundSpu) {
|
|
37
|
+
throw ConflictRequestError("Spu already exists");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// create new spu
|
|
41
|
+
const newSpu = await SPU.create({
|
|
42
|
+
spu_id: randomSpuId(),
|
|
43
|
+
spu_name,
|
|
44
|
+
spu_slug,
|
|
45
|
+
spu_description,
|
|
46
|
+
spu_images,
|
|
47
|
+
spu_category,
|
|
48
|
+
spu_price,
|
|
49
|
+
spu_shop,
|
|
50
|
+
spu_attributes,
|
|
51
|
+
spu_ratingsAverage,
|
|
52
|
+
spu_variations,
|
|
53
|
+
spu_quantity,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// if sku_list is not empty, create skus list
|
|
57
|
+
if (newSpu && sku_list.length > 0) {
|
|
58
|
+
// 3. create skus list
|
|
59
|
+
await SKUService.createNewSku({
|
|
60
|
+
spu_id: newSpu.spu_id,
|
|
61
|
+
sku_list,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 4. sync data via elasticsearch (search service)
|
|
66
|
+
|
|
67
|
+
// return newSpu
|
|
68
|
+
return newSpu;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
throw new Error(error);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
static getDetailSpu = async ({ spu_id }) => {
|
|
75
|
+
const foundSpu = await findSpuById({ spu_id, isPublished: true });
|
|
76
|
+
if (!foundSpu) {
|
|
77
|
+
throw NotFoundError("Spu not found");
|
|
78
|
+
}
|
|
79
|
+
const foundSkuList = await SKUService.getListSkuBySpuId({ spu_id });
|
|
80
|
+
return {
|
|
81
|
+
spu_info: _.omit(foundSpu, ["__v", "updatedAt"]),
|
|
82
|
+
sku_list: foundSkuList.map((sku) =>
|
|
83
|
+
_.omit(sku, ["__v", "updatedAt", "createdAt", "isDeleted"])
|
|
84
|
+
),
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = SPUService;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { NotFoundError } = require("../core/error.response");
|
|
4
|
+
const { Template } = require("../models/template.model");
|
|
5
|
+
const { generateTemplateHtml } = require("../utils/template.html");
|
|
6
|
+
|
|
7
|
+
class TemplateService {
|
|
8
|
+
static async getTemplate({ template_name = null }) {
|
|
9
|
+
// check if template_id exists
|
|
10
|
+
const template = await Template.findOne({ template_name }).lean().exec();
|
|
11
|
+
if (!template) {
|
|
12
|
+
throw new NotFoundError("Template not found");
|
|
13
|
+
}
|
|
14
|
+
return template;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static async createTemplate({
|
|
18
|
+
template_id = null,
|
|
19
|
+
template_name = null,
|
|
20
|
+
template_html = null,
|
|
21
|
+
}) {
|
|
22
|
+
// check if template_id exists
|
|
23
|
+
const template = await Template.findOne({ template_name }).lean().exec();
|
|
24
|
+
if (template) {
|
|
25
|
+
throw new BadRequestError("Template already exists");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const templateHtml = template_html || generateTemplateHtml();
|
|
29
|
+
|
|
30
|
+
// create template
|
|
31
|
+
const newTemplate = await Template.create({
|
|
32
|
+
template_id,
|
|
33
|
+
template_name,
|
|
34
|
+
template_html: templateHtml,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return newTemplate;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = TemplateService;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
s3,
|
|
5
|
+
PutObjectCommand,
|
|
6
|
+
GetObjectCommand,
|
|
7
|
+
} = require("../config/config.aws-s3");
|
|
8
|
+
const { BadRequestError } = require("../core/error.response");
|
|
9
|
+
// const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
|
|
10
|
+
const { getSignedUrl } = require("@aws-sdk/cloudfront-signer");
|
|
11
|
+
const cloudfrontDomain = process.env.AWS_CLOUDFRONT_DOMAIN;
|
|
12
|
+
|
|
13
|
+
class UploadAwsService {
|
|
14
|
+
static async uploadImageFromLocalS3({ file }) {
|
|
15
|
+
try {
|
|
16
|
+
if (!file) {
|
|
17
|
+
throw new BadRequestError("No file provided");
|
|
18
|
+
}
|
|
19
|
+
const imageName = `${Date.now()}-${file.originalname}`;
|
|
20
|
+
// put to s3 first
|
|
21
|
+
const commandForPut = new PutObjectCommand({
|
|
22
|
+
Bucket: process.env.AWS_BUCKET_NAME,
|
|
23
|
+
Key: imageName,
|
|
24
|
+
Body: file.buffer,
|
|
25
|
+
ContentType: "image/jpeg",
|
|
26
|
+
});
|
|
27
|
+
const result = await s3.send(commandForPut);
|
|
28
|
+
|
|
29
|
+
// s3
|
|
30
|
+
// using getSignedUrl to publish the url to the community
|
|
31
|
+
// const commandForRead = new GetObjectCommand({
|
|
32
|
+
// Bucket: process.env.AWS_BUCKET_NAME,
|
|
33
|
+
// Key: imageName,
|
|
34
|
+
// });
|
|
35
|
+
|
|
36
|
+
// cloudfront signer
|
|
37
|
+
const signedUrl = await getSignedUrl({
|
|
38
|
+
url: `${cloudfrontDomain}/${imageName}`,
|
|
39
|
+
dateLessThan: new Date(Date.now() + 1000 * 60),
|
|
40
|
+
keyPairId: process.env.AWS_CLOUDFRONT_PUBLIC_KEY_ID,
|
|
41
|
+
privateKey: process.env.AWS_CLOUDFRONT_PRIVATE_KEY,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
url: signedUrl,
|
|
46
|
+
result,
|
|
47
|
+
};
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(error);
|
|
50
|
+
throw new BadRequestError(error.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = UploadAwsService;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const cloudinary = require("../config/config.cloudinary");
|
|
4
|
+
|
|
5
|
+
class UploadService {
|
|
6
|
+
static async uploadImageFromUrl({ url }) {
|
|
7
|
+
try {
|
|
8
|
+
// Implement logic to upload image from URL
|
|
9
|
+
const urlImage = url;
|
|
10
|
+
// Return the uploaded file's path
|
|
11
|
+
const folderName = "products/upload";
|
|
12
|
+
const fileName = "product_image.jpg";
|
|
13
|
+
const result = await cloudinary.uploader.upload(urlImage, {
|
|
14
|
+
folder: folderName,
|
|
15
|
+
public_id: fileName,
|
|
16
|
+
use_filename: true,
|
|
17
|
+
overwrite: true,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
url: result.secure_url,
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(error);
|
|
24
|
+
throw new BadRequestError(error.message);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static async uploadImageFromLocal({ path, folderName = "products/upload" }) {
|
|
29
|
+
try {
|
|
30
|
+
// Return the uploaded file's path
|
|
31
|
+
console.log("running upload");
|
|
32
|
+
const fileName = "product_image";
|
|
33
|
+
const result = await cloudinary.uploader.upload(path, {
|
|
34
|
+
folder: folderName,
|
|
35
|
+
public_id: fileName,
|
|
36
|
+
use_filename: true,
|
|
37
|
+
overwrite: true,
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
url: result.secure_url,
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(error);
|
|
44
|
+
throw new BadRequestError(error.message);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static async uploadImagesFromLocal({
|
|
49
|
+
files,
|
|
50
|
+
folderName = "products/upload",
|
|
51
|
+
}) {
|
|
52
|
+
try {
|
|
53
|
+
// Return the uploaded file's path
|
|
54
|
+
if (!files.length) return;
|
|
55
|
+
const uploaded_urls = [];
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
const result = await cloudinary.uploader.upload(file.path, {
|
|
58
|
+
folder: folderName,
|
|
59
|
+
use_filename: true,
|
|
60
|
+
overwrite: true,
|
|
61
|
+
});
|
|
62
|
+
uploaded_urls.push(result.secure_url);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
uploaded_urls,
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(error);
|
|
69
|
+
throw new BadRequestError(error.message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = UploadService;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { BadRequestError } = require("../core/error.response");
|
|
4
|
+
const { OtpService } = require("../services/otp.service");
|
|
5
|
+
const { User } = require("../models/user.model");
|
|
6
|
+
const bcrypt = require("bcrypt");
|
|
7
|
+
const crypto = require("crypto");
|
|
8
|
+
const { createTokenPair } = require("../utils/jwt");
|
|
9
|
+
const { getInfoData } = require("../utils/data");
|
|
10
|
+
const { createUser } = require("../models/repository/user.repo");
|
|
11
|
+
const Role = require("../models/role.model");
|
|
12
|
+
|
|
13
|
+
class UserService {
|
|
14
|
+
static async findUserByEmail({ email = null }) {
|
|
15
|
+
const user = await User.findOne({ email }).lean().exec();
|
|
16
|
+
return user;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static async checkRegisterEmailToken({ email = null, token = null }) {
|
|
20
|
+
const otp = await OtpService.checkOtp({ email, token });
|
|
21
|
+
if (!otp) {
|
|
22
|
+
throw new BadRequestError("Invalid token");
|
|
23
|
+
}
|
|
24
|
+
const { otp_email: email } = otp;
|
|
25
|
+
const user = await UserService.findUserByEmail({ email });
|
|
26
|
+
if (user) {
|
|
27
|
+
throw new BadRequestError("Email already registered");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const hassPassword = await bcrypt.hash(email, 10);
|
|
31
|
+
const role = await Role.findOne({ role_name: "user" });
|
|
32
|
+
const newUser = await createUser({
|
|
33
|
+
user_id: 1,
|
|
34
|
+
user_name: email,
|
|
35
|
+
user_email: email,
|
|
36
|
+
user_password: hassPassword,
|
|
37
|
+
user_role: role._id,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (newUser) {
|
|
41
|
+
const privateKey = crypto.randomBytes(64).toString("hex");
|
|
42
|
+
const publicKey = crypto.randomBytes(64).toString("hex");
|
|
43
|
+
const tokens = await createTokenPair(
|
|
44
|
+
{
|
|
45
|
+
userId: newUser._id,
|
|
46
|
+
email,
|
|
47
|
+
},
|
|
48
|
+
privateKey,
|
|
49
|
+
publicKey
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const keyStore = await KeyTokenService.createKeyToken({
|
|
53
|
+
userId: newUser._id,
|
|
54
|
+
publicKey,
|
|
55
|
+
privateKey,
|
|
56
|
+
refreshToken: tokens.refreshToken,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (!keyStore) {
|
|
60
|
+
throw new BadRequestError("Error: Public key string error");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
user: getInfoData({
|
|
65
|
+
fields: ["_id", "name", "email"],
|
|
66
|
+
object: newUser,
|
|
67
|
+
}),
|
|
68
|
+
tokens,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
message: "Verify email successfully",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static async newUser({ email = null, captcha = null }) {
|
|
78
|
+
// check if email is already registered
|
|
79
|
+
const user = await User.findOne({ email }).lean().exec();
|
|
80
|
+
if (user) {
|
|
81
|
+
throw new BadRequestError("Email already registered");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// check if captcha is valid
|
|
85
|
+
// send otp to emai
|
|
86
|
+
return {
|
|
87
|
+
message: "Send otp to email successfully",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = UserService();
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// inventory.test.js
|
|
2
|
+
const redisPubSubService = require("../services/redisPubSub.service");
|
|
3
|
+
|
|
4
|
+
class InventoryServiceTest {
|
|
5
|
+
constructor() {
|
|
6
|
+
// Subscribe to Redis channel
|
|
7
|
+
redisPubSubService.subscribe("purchase", function (channel, message) {
|
|
8
|
+
console.log("Received message:", message);
|
|
9
|
+
// Assuming InventoryServiceTest.updateInventory is static
|
|
10
|
+
InventoryServiceTest.updateInventory(JSON.parse(message));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static updateInventory({ productId, quantity }) {
|
|
15
|
+
console.log(
|
|
16
|
+
`Updating inventory for product ${productId} with quantity ${quantity}`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = new InventoryServiceTest();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { Kafka, logLevel } = require("kafkajs");
|
|
2
|
+
|
|
3
|
+
const kafka = new Kafka({
|
|
4
|
+
clientId: "my-app",
|
|
5
|
+
brokers: ["localhost:9092"],
|
|
6
|
+
logLevel: logLevel.name,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const consumer = kafka.consumer({ groupId: "test-group" });
|
|
10
|
+
|
|
11
|
+
const runConsumer = async () => {
|
|
12
|
+
await consumer.connect();
|
|
13
|
+
await consumer.subscribe({ topic: "test-topic", fromBeginning: true });
|
|
14
|
+
await consumer.run({
|
|
15
|
+
eachMessage: async ({ topic, partition, message }) => {
|
|
16
|
+
console.log({
|
|
17
|
+
value: message.value.toString(),
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
runConsumer().catch((err) => console.log(err));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { Kafka, logLevel } = require("kafkajs");
|
|
2
|
+
|
|
3
|
+
const kafka = new Kafka({
|
|
4
|
+
clientId: "my-app",
|
|
5
|
+
brokers: ["localhost:9092"],
|
|
6
|
+
logLevel: logLevel.NOTHING
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const producer = kafka.producer();
|
|
10
|
+
|
|
11
|
+
const runProducer = async () => {
|
|
12
|
+
await producer.connect();
|
|
13
|
+
await producer.send({
|
|
14
|
+
topic: "test-topic",
|
|
15
|
+
messages: [{ value: "Hello KafkaJS user!" }],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await producer.disconnect();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
runProducer().catch((err) => console.log(err));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const amqp = require("amqplib");
|
|
2
|
+
|
|
3
|
+
const runConsumer = async () => {
|
|
4
|
+
try {
|
|
5
|
+
const connection = await amqp.connect("amqp://localhost:5672");
|
|
6
|
+
const channel = await connection.createChannel();
|
|
7
|
+
const queueName = "test-topic";
|
|
8
|
+
|
|
9
|
+
await channel.assertQueue(queueName, {
|
|
10
|
+
durable: true,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
channel.consume(
|
|
14
|
+
queueName,
|
|
15
|
+
(message) => {
|
|
16
|
+
console.log(`message_received:::${message.content.toString()}`);
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
// avoid dupliacte messages if client already received the message
|
|
20
|
+
noAck: true,
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.log("Error rabbitmq: ", error);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
runConsumer().catch((err) => console.log(err));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const amqp = require("amqplib");
|
|
4
|
+
|
|
5
|
+
const consumeOrderedMessages = async () => {
|
|
6
|
+
const connection = await amqp.connect("amqp://localhost:5672");
|
|
7
|
+
const channel = await connection.createChannel();
|
|
8
|
+
const queueName = "ordered_queue";
|
|
9
|
+
|
|
10
|
+
await channel.assertQueue(queueName, {
|
|
11
|
+
durable: true
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Set prefetch to 1 to ensure only one message is processed at a time until it is acknowledged
|
|
15
|
+
channel.prefetch(1);
|
|
16
|
+
|
|
17
|
+
channel.consume(queueName, (message) => {
|
|
18
|
+
const msg = message.content.toString();
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
console.log("Processed: ", msg);
|
|
21
|
+
channel.ack(message);
|
|
22
|
+
}, Math.random() * 1000);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
consumeOrderedMessages().catch((err) => console.log(err));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const amqp = require("amqplib");
|
|
4
|
+
|
|
5
|
+
const produceOrderedMessages = async () => {
|
|
6
|
+
const connection = await amqp.connect("amqp://localhost:5672");
|
|
7
|
+
const channel = await connection.createChannel();
|
|
8
|
+
const queueName = "ordered_queue";
|
|
9
|
+
|
|
10
|
+
await channel.assertQueue(queueName, {
|
|
11
|
+
durable: true,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < 10; i++) {
|
|
15
|
+
await channel.sendToQueue(
|
|
16
|
+
queueName,
|
|
17
|
+
Buffer.from(`Ordered Message:::${i}`),
|
|
18
|
+
{
|
|
19
|
+
persistent: true,
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
console.log(`message_ordered_sent:::${i}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
connection.close();
|
|
27
|
+
console.log("Connection closed");
|
|
28
|
+
}, 1000);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
produceOrderedMessages().catch((err) => console.log(err));
|