nestforge-generator 0.1.0

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.
Files changed (326) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +371 -0
  3. package/README.pt-BR.md +370 -0
  4. package/dist/features/auth-strategy.js +19 -0
  5. package/dist/features/auth-strategy.js.map +1 -0
  6. package/dist/features/database.js +59 -0
  7. package/dist/features/database.js.map +1 -0
  8. package/dist/features/dependencies.js +57 -0
  9. package/dist/features/dependencies.js.map +1 -0
  10. package/dist/features/language.js +172 -0
  11. package/dist/features/language.js.map +1 -0
  12. package/dist/features/markers.js +116 -0
  13. package/dist/features/markers.js.map +1 -0
  14. package/dist/generator.js +120 -0
  15. package/dist/generator.js.map +1 -0
  16. package/dist/index.js +59 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/prompts.js +137 -0
  19. package/dist/prompts.js.map +1 -0
  20. package/package.json +76 -0
  21. package/templates/drizzle/.env.example +45 -0
  22. package/templates/drizzle/.env.test +38 -0
  23. package/templates/drizzle/.github/workflows/ci.yml +119 -0
  24. package/templates/drizzle/ARCHITECTURE.md +227 -0
  25. package/templates/drizzle/ARCHITECTURE.pt-BR.md +225 -0
  26. package/templates/drizzle/CODE_OF_CONDUCT.md +29 -0
  27. package/templates/drizzle/CODE_OF_CONDUCT.pt-BR.md +27 -0
  28. package/templates/drizzle/CONTRIBUTING.md +57 -0
  29. package/templates/drizzle/CONTRIBUTING.pt-BR.md +54 -0
  30. package/templates/drizzle/Dockerfile +43 -0
  31. package/templates/drizzle/LICENSE +21 -0
  32. package/templates/drizzle/README.md +257 -0
  33. package/templates/drizzle/README.pt-BR.md +257 -0
  34. package/templates/drizzle/ROADMAP.md +143 -0
  35. package/templates/drizzle/ROADMAP.pt-BR.md +143 -0
  36. package/templates/drizzle/TESTING.md +136 -0
  37. package/templates/drizzle/TESTING.pt-BR.md +136 -0
  38. package/templates/drizzle/docker-compose.yml +82 -0
  39. package/templates/drizzle/docs/adding-a-module.md +585 -0
  40. package/templates/drizzle/docs/features-markers.md +457 -0
  41. package/templates/drizzle/drizzle.config.ts +49 -0
  42. package/templates/drizzle/nest-cli.json +8 -0
  43. package/templates/drizzle/package.json +96 -0
  44. package/templates/drizzle/src/app.module.ts +72 -0
  45. package/templates/drizzle/src/auth/auth.controller.ts +283 -0
  46. package/templates/drizzle/src/auth/auth.module.ts +81 -0
  47. package/templates/drizzle/src/auth/auth.service.spec.ts +111 -0
  48. package/templates/drizzle/src/auth/auth.service.ts +631 -0
  49. package/templates/drizzle/src/auth/drizzle-session.store.ts +263 -0
  50. package/templates/drizzle/src/auth/dto/forgot-password.dto.ts +9 -0
  51. package/templates/drizzle/src/auth/dto/login.dto.ts +10 -0
  52. package/templates/drizzle/src/auth/dto/refresh-token.dto.ts +9 -0
  53. package/templates/drizzle/src/auth/dto/register.dto.ts +11 -0
  54. package/templates/drizzle/src/auth/dto/reset-password.dto.ts +10 -0
  55. package/templates/drizzle/src/auth/guards/github-auth.guard.ts +10 -0
  56. package/templates/drizzle/src/auth/guards/google-auth.guard.ts +10 -0
  57. package/templates/drizzle/src/auth/guards/jwt-auth.guard.ts +25 -0
  58. package/templates/drizzle/src/auth/guards/session-auth.guard.spec.ts +77 -0
  59. package/templates/drizzle/src/auth/guards/session-auth.guard.ts +37 -0
  60. package/templates/drizzle/src/auth/session.service.spec.ts +74 -0
  61. package/templates/drizzle/src/auth/session.service.ts +96 -0
  62. package/templates/drizzle/src/auth/strategies/github.strategy.ts +41 -0
  63. package/templates/drizzle/src/auth/strategies/google.strategy.ts +43 -0
  64. package/templates/drizzle/src/auth/strategies/jwt.strategy.ts +25 -0
  65. package/templates/drizzle/src/auth/token.service.ts +175 -0
  66. package/templates/drizzle/src/common/constants/permissions.ts +8 -0
  67. package/templates/drizzle/src/common/constants/role-permissions.ts +9 -0
  68. package/templates/drizzle/src/common/constants/role.enum.ts +5 -0
  69. package/templates/drizzle/src/common/decorators/current-user.decorator.ts +8 -0
  70. package/templates/drizzle/src/common/decorators/permissions.decorator.ts +7 -0
  71. package/templates/drizzle/src/common/decorators/public.decorator.ts +4 -0
  72. package/templates/drizzle/src/common/decorators/roles.decorator.ts +6 -0
  73. package/templates/drizzle/src/common/filters/http-exception.filter.ts +34 -0
  74. package/templates/drizzle/src/common/guards/permissions.guard.spec.ts +54 -0
  75. package/templates/drizzle/src/common/guards/permissions.guard.ts +28 -0
  76. package/templates/drizzle/src/common/guards/roles.guard.spec.ts +37 -0
  77. package/templates/drizzle/src/common/guards/roles.guard.ts +24 -0
  78. package/templates/drizzle/src/common/interceptors/logging.interceptor.ts +23 -0
  79. package/templates/drizzle/src/common/middleware/csrf.middleware.spec.ts +97 -0
  80. package/templates/drizzle/src/common/middleware/csrf.middleware.ts +46 -0
  81. package/templates/drizzle/src/common/utils/avatar-storage.util.ts +32 -0
  82. package/templates/drizzle/src/common/utils/hash.util.ts +5 -0
  83. package/templates/drizzle/src/config/env.validation.ts +50 -0
  84. package/templates/drizzle/src/database/database-lifecycle.service.ts +30 -0
  85. package/templates/drizzle/src/database/database.constants.ts +2 -0
  86. package/templates/drizzle/src/database/database.decorators.ts +5 -0
  87. package/templates/drizzle/src/database/database.module.ts +96 -0
  88. package/templates/drizzle/src/database/database.types.ts +28 -0
  89. package/templates/drizzle/src/database/schema/index.ts +11 -0
  90. package/templates/drizzle/src/database/schema/mysql.schema.ts +215 -0
  91. package/templates/drizzle/src/database/schema/postgres.schema.ts +218 -0
  92. package/templates/drizzle/src/database/schema/sqlite.schema.ts +190 -0
  93. package/templates/drizzle/src/database/seed.ts +152 -0
  94. package/templates/drizzle/src/health/health.controller.ts +49 -0
  95. package/templates/drizzle/src/health/health.module.ts +19 -0
  96. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.spec.ts +71 -0
  97. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.ts +52 -0
  98. package/templates/drizzle/src/health/indicators/redis-health.indicator.spec.ts +54 -0
  99. package/templates/drizzle/src/health/indicators/redis-health.indicator.ts +33 -0
  100. package/templates/drizzle/src/mail/mail.module.ts +12 -0
  101. package/templates/drizzle/src/mail/mail.processor.ts +48 -0
  102. package/templates/drizzle/src/mail/mail.service.ts +24 -0
  103. package/templates/drizzle/src/mail/templates/email-templates.ts +28 -0
  104. package/templates/drizzle/src/main.ts +145 -0
  105. package/templates/drizzle/src/metrics/metrics.controller.ts +22 -0
  106. package/templates/drizzle/src/metrics/metrics.interceptor.ts +30 -0
  107. package/templates/drizzle/src/metrics/metrics.module.ts +12 -0
  108. package/templates/drizzle/src/metrics/metrics.service.ts +34 -0
  109. package/templates/drizzle/src/types/express-session.d.ts +13 -0
  110. package/templates/drizzle/src/users/dto/create-user.dto.ts +12 -0
  111. package/templates/drizzle/src/users/dto/find-users-query.dto.ts +12 -0
  112. package/templates/drizzle/src/users/dto/update-user.dto.ts +6 -0
  113. package/templates/drizzle/src/users/entities/user.entity.ts +23 -0
  114. package/templates/drizzle/src/users/users.controller.ts +165 -0
  115. package/templates/drizzle/src/users/users.module.ts +10 -0
  116. package/templates/drizzle/src/users/users.service.spec.ts +301 -0
  117. package/templates/drizzle/src/users/users.service.ts +213 -0
  118. package/templates/drizzle/test/auth.e2e-spec.ts +114 -0
  119. package/templates/drizzle/test/session-auth.e2e-spec.ts +163 -0
  120. package/templates/drizzle/test/users.e2e-spec.ts +212 -0
  121. package/templates/drizzle/test/utils/clean-database.ts +104 -0
  122. package/templates/drizzle/test/utils/e2e-setup.ts +77 -0
  123. package/templates/drizzle/tsconfig.build.json +4 -0
  124. package/templates/drizzle/tsconfig.json +25 -0
  125. package/templates/drizzle/vitest.config.ts +20 -0
  126. package/templates/drizzle/vitest.e2e.config.ts +19 -0
  127. package/templates/prisma/.env.example +44 -0
  128. package/templates/prisma/.env.test +37 -0
  129. package/templates/prisma/.github/workflows/ci.yml +109 -0
  130. package/templates/prisma/ARCHITECTURE.md +70 -0
  131. package/templates/prisma/ARCHITECTURE.pt-BR.md +63 -0
  132. package/templates/prisma/CODE_OF_CONDUCT.md +29 -0
  133. package/templates/prisma/CODE_OF_CONDUCT.pt-BR.md +27 -0
  134. package/templates/prisma/CONTRIBUTING.md +57 -0
  135. package/templates/prisma/CONTRIBUTING.pt-BR.md +54 -0
  136. package/templates/prisma/Dockerfile +33 -0
  137. package/templates/prisma/LICENSE +21 -0
  138. package/templates/prisma/README.md +267 -0
  139. package/templates/prisma/README.pt-BR.md +267 -0
  140. package/templates/prisma/ROADMAP.md +75 -0
  141. package/templates/prisma/ROADMAP.pt-BR.md +65 -0
  142. package/templates/prisma/TESTING.md +123 -0
  143. package/templates/prisma/TESTING.pt-BR.md +123 -0
  144. package/templates/prisma/docker-compose.yml +78 -0
  145. package/templates/prisma/docs/adding-a-module.md +230 -0
  146. package/templates/prisma/docs/features-markers.md +50 -0
  147. package/templates/prisma/nest-cli.json +8 -0
  148. package/templates/prisma/package.json +95 -0
  149. package/templates/prisma/prisma/schema.prisma +105 -0
  150. package/templates/prisma/prisma/seed.ts +46 -0
  151. package/templates/prisma/src/app.module.ts +72 -0
  152. package/templates/prisma/src/auth/auth.controller.ts +283 -0
  153. package/templates/prisma/src/auth/auth.module.ts +59 -0
  154. package/templates/prisma/src/auth/auth.service.spec.ts +53 -0
  155. package/templates/prisma/src/auth/auth.service.ts +224 -0
  156. package/templates/prisma/src/auth/dto/forgot-password.dto.ts +9 -0
  157. package/templates/prisma/src/auth/dto/login.dto.ts +10 -0
  158. package/templates/prisma/src/auth/dto/refresh-token.dto.ts +9 -0
  159. package/templates/prisma/src/auth/dto/register.dto.ts +11 -0
  160. package/templates/prisma/src/auth/dto/reset-password.dto.ts +10 -0
  161. package/templates/prisma/src/auth/guards/github-auth.guard.ts +10 -0
  162. package/templates/prisma/src/auth/guards/google-auth.guard.ts +10 -0
  163. package/templates/prisma/src/auth/guards/jwt-auth.guard.ts +25 -0
  164. package/templates/prisma/src/auth/guards/session-auth.guard.spec.ts +77 -0
  165. package/templates/prisma/src/auth/guards/session-auth.guard.ts +37 -0
  166. package/templates/prisma/src/auth/session.service.spec.ts +74 -0
  167. package/templates/prisma/src/auth/session.service.ts +96 -0
  168. package/templates/prisma/src/auth/strategies/github.strategy.ts +41 -0
  169. package/templates/prisma/src/auth/strategies/google.strategy.ts +43 -0
  170. package/templates/prisma/src/auth/strategies/jwt.strategy.ts +25 -0
  171. package/templates/prisma/src/auth/token.service.ts +84 -0
  172. package/templates/prisma/src/common/constants/permissions.ts +8 -0
  173. package/templates/prisma/src/common/constants/role-permissions.ts +9 -0
  174. package/templates/prisma/src/common/decorators/current-user.decorator.ts +8 -0
  175. package/templates/prisma/src/common/decorators/permissions.decorator.ts +7 -0
  176. package/templates/prisma/src/common/decorators/public.decorator.ts +4 -0
  177. package/templates/prisma/src/common/decorators/roles.decorator.ts +6 -0
  178. package/templates/prisma/src/common/filters/http-exception.filter.ts +34 -0
  179. package/templates/prisma/src/common/guards/permissions.guard.spec.ts +54 -0
  180. package/templates/prisma/src/common/guards/permissions.guard.ts +28 -0
  181. package/templates/prisma/src/common/guards/roles.guard.spec.ts +37 -0
  182. package/templates/prisma/src/common/guards/roles.guard.ts +24 -0
  183. package/templates/prisma/src/common/interceptors/logging.interceptor.ts +23 -0
  184. package/templates/prisma/src/common/middleware/csrf.middleware.spec.ts +97 -0
  185. package/templates/prisma/src/common/middleware/csrf.middleware.ts +46 -0
  186. package/templates/prisma/src/common/utils/avatar-storage.util.ts +32 -0
  187. package/templates/prisma/src/common/utils/hash.util.ts +5 -0
  188. package/templates/prisma/src/config/env.validation.ts +49 -0
  189. package/templates/prisma/src/database/prisma.module.ts +9 -0
  190. package/templates/prisma/src/database/prisma.service.ts +13 -0
  191. package/templates/prisma/src/health/health.controller.ts +49 -0
  192. package/templates/prisma/src/health/health.module.ts +19 -0
  193. package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +22 -0
  194. package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +19 -0
  195. package/templates/prisma/src/health/indicators/redis-health.indicator.spec.ts +54 -0
  196. package/templates/prisma/src/health/indicators/redis-health.indicator.ts +33 -0
  197. package/templates/prisma/src/mail/mail.module.ts +12 -0
  198. package/templates/prisma/src/mail/mail.processor.ts +48 -0
  199. package/templates/prisma/src/mail/mail.service.ts +24 -0
  200. package/templates/prisma/src/mail/templates/email-templates.ts +28 -0
  201. package/templates/prisma/src/main.ts +92 -0
  202. package/templates/prisma/src/metrics/metrics.controller.ts +22 -0
  203. package/templates/prisma/src/metrics/metrics.interceptor.ts +30 -0
  204. package/templates/prisma/src/metrics/metrics.module.ts +12 -0
  205. package/templates/prisma/src/metrics/metrics.service.ts +34 -0
  206. package/templates/prisma/src/types/express-session.d.ts +13 -0
  207. package/templates/prisma/src/users/dto/create-user.dto.ts +12 -0
  208. package/templates/prisma/src/users/dto/find-users-query.dto.ts +12 -0
  209. package/templates/prisma/src/users/dto/update-user.dto.ts +6 -0
  210. package/templates/prisma/src/users/entities/user.entity.ts +20 -0
  211. package/templates/prisma/src/users/users.controller.ts +165 -0
  212. package/templates/prisma/src/users/users.module.ts +10 -0
  213. package/templates/prisma/src/users/users.service.spec.ts +104 -0
  214. package/templates/prisma/src/users/users.service.ts +114 -0
  215. package/templates/prisma/test/auth.e2e-spec.ts +75 -0
  216. package/templates/prisma/test/session-auth.e2e-spec.ts +163 -0
  217. package/templates/prisma/test/users.e2e-spec.ts +106 -0
  218. package/templates/prisma/test/utils/clean-database.ts +14 -0
  219. package/templates/prisma/test/utils/e2e-setup.ts +58 -0
  220. package/templates/prisma/tsconfig.build.json +4 -0
  221. package/templates/prisma/tsconfig.json +25 -0
  222. package/templates/prisma/vitest.config.ts +20 -0
  223. package/templates/prisma/vitest.e2e.config.ts +19 -0
  224. package/templates/typeorm/.env.example +45 -0
  225. package/templates/typeorm/.env.test +38 -0
  226. package/templates/typeorm/.github/workflows/ci.yml +116 -0
  227. package/templates/typeorm/ARCHITECTURE.md +158 -0
  228. package/templates/typeorm/ARCHITECTURE.pt-BR.md +156 -0
  229. package/templates/typeorm/CODE_OF_CONDUCT.md +29 -0
  230. package/templates/typeorm/CODE_OF_CONDUCT.pt-BR.md +27 -0
  231. package/templates/typeorm/CONTRIBUTING.md +57 -0
  232. package/templates/typeorm/CONTRIBUTING.pt-BR.md +54 -0
  233. package/templates/typeorm/Dockerfile +43 -0
  234. package/templates/typeorm/LICENSE +21 -0
  235. package/templates/typeorm/README.md +266 -0
  236. package/templates/typeorm/README.pt-BR.md +266 -0
  237. package/templates/typeorm/ROADMAP.md +79 -0
  238. package/templates/typeorm/ROADMAP.pt-BR.md +67 -0
  239. package/templates/typeorm/TESTING.md +114 -0
  240. package/templates/typeorm/TESTING.pt-BR.md +114 -0
  241. package/templates/typeorm/docker-compose.yml +78 -0
  242. package/templates/typeorm/docs/adding-a-module.md +369 -0
  243. package/templates/typeorm/docs/features-markers.md +50 -0
  244. package/templates/typeorm/nest-cli.json +8 -0
  245. package/templates/typeorm/package.json +98 -0
  246. package/templates/typeorm/src/app.module.ts +72 -0
  247. package/templates/typeorm/src/auth/auth.controller.ts +283 -0
  248. package/templates/typeorm/src/auth/auth.module.ts +86 -0
  249. package/templates/typeorm/src/auth/auth.service.spec.ts +111 -0
  250. package/templates/typeorm/src/auth/auth.service.ts +346 -0
  251. package/templates/typeorm/src/auth/dto/forgot-password.dto.ts +9 -0
  252. package/templates/typeorm/src/auth/dto/login.dto.ts +10 -0
  253. package/templates/typeorm/src/auth/dto/refresh-token.dto.ts +9 -0
  254. package/templates/typeorm/src/auth/dto/register.dto.ts +11 -0
  255. package/templates/typeorm/src/auth/dto/reset-password.dto.ts +10 -0
  256. package/templates/typeorm/src/auth/entities/email-verification-token.entity.ts +69 -0
  257. package/templates/typeorm/src/auth/entities/oauth-account.entity.ts +50 -0
  258. package/templates/typeorm/src/auth/entities/password-reset-token.entity.ts +69 -0
  259. package/templates/typeorm/src/auth/entities/refresh-token.entity.ts +69 -0
  260. package/templates/typeorm/src/auth/entities/session.entity.ts +50 -0
  261. package/templates/typeorm/src/auth/guards/github-auth.guard.ts +10 -0
  262. package/templates/typeorm/src/auth/guards/google-auth.guard.ts +10 -0
  263. package/templates/typeorm/src/auth/guards/jwt-auth.guard.ts +25 -0
  264. package/templates/typeorm/src/auth/guards/session-auth.guard.spec.ts +77 -0
  265. package/templates/typeorm/src/auth/guards/session-auth.guard.ts +37 -0
  266. package/templates/typeorm/src/auth/session.service.spec.ts +74 -0
  267. package/templates/typeorm/src/auth/session.service.ts +96 -0
  268. package/templates/typeorm/src/auth/strategies/github.strategy.ts +41 -0
  269. package/templates/typeorm/src/auth/strategies/google.strategy.ts +43 -0
  270. package/templates/typeorm/src/auth/strategies/jwt.strategy.ts +25 -0
  271. package/templates/typeorm/src/auth/token.service.ts +115 -0
  272. package/templates/typeorm/src/common/constants/permissions.ts +8 -0
  273. package/templates/typeorm/src/common/constants/role-permissions.ts +9 -0
  274. package/templates/typeorm/src/common/constants/role.enum.ts +5 -0
  275. package/templates/typeorm/src/common/decorators/current-user.decorator.ts +8 -0
  276. package/templates/typeorm/src/common/decorators/permissions.decorator.ts +7 -0
  277. package/templates/typeorm/src/common/decorators/public.decorator.ts +4 -0
  278. package/templates/typeorm/src/common/decorators/roles.decorator.ts +6 -0
  279. package/templates/typeorm/src/common/filters/http-exception.filter.ts +34 -0
  280. package/templates/typeorm/src/common/guards/permissions.guard.spec.ts +54 -0
  281. package/templates/typeorm/src/common/guards/permissions.guard.ts +28 -0
  282. package/templates/typeorm/src/common/guards/roles.guard.spec.ts +37 -0
  283. package/templates/typeorm/src/common/guards/roles.guard.ts +24 -0
  284. package/templates/typeorm/src/common/interceptors/logging.interceptor.ts +23 -0
  285. package/templates/typeorm/src/common/middleware/csrf.middleware.spec.ts +97 -0
  286. package/templates/typeorm/src/common/middleware/csrf.middleware.ts +46 -0
  287. package/templates/typeorm/src/common/utils/avatar-storage.util.ts +32 -0
  288. package/templates/typeorm/src/common/utils/hash.util.ts +5 -0
  289. package/templates/typeorm/src/config/env.validation.ts +50 -0
  290. package/templates/typeorm/src/database/data-source.ts +20 -0
  291. package/templates/typeorm/src/database/database.module.ts +39 -0
  292. package/templates/typeorm/src/database/seed.ts +81 -0
  293. package/templates/typeorm/src/database/typeorm-options.ts +49 -0
  294. package/templates/typeorm/src/health/health.controller.ts +49 -0
  295. package/templates/typeorm/src/health/health.module.ts +19 -0
  296. package/templates/typeorm/src/health/indicators/redis-health.indicator.spec.ts +54 -0
  297. package/templates/typeorm/src/health/indicators/redis-health.indicator.ts +33 -0
  298. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.spec.ts +49 -0
  299. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.ts +37 -0
  300. package/templates/typeorm/src/mail/mail.module.ts +12 -0
  301. package/templates/typeorm/src/mail/mail.processor.ts +48 -0
  302. package/templates/typeorm/src/mail/mail.service.ts +24 -0
  303. package/templates/typeorm/src/mail/templates/email-templates.ts +28 -0
  304. package/templates/typeorm/src/main.ts +107 -0
  305. package/templates/typeorm/src/metrics/metrics.controller.ts +22 -0
  306. package/templates/typeorm/src/metrics/metrics.interceptor.ts +30 -0
  307. package/templates/typeorm/src/metrics/metrics.module.ts +12 -0
  308. package/templates/typeorm/src/metrics/metrics.service.ts +34 -0
  309. package/templates/typeorm/src/types/express-session.d.ts +13 -0
  310. package/templates/typeorm/src/users/dto/create-user.dto.ts +12 -0
  311. package/templates/typeorm/src/users/dto/find-users-query.dto.ts +12 -0
  312. package/templates/typeorm/src/users/dto/update-user.dto.ts +6 -0
  313. package/templates/typeorm/src/users/entities/user.entity.ts +113 -0
  314. package/templates/typeorm/src/users/users.controller.ts +165 -0
  315. package/templates/typeorm/src/users/users.module.ts +13 -0
  316. package/templates/typeorm/src/users/users.service.spec.ts +183 -0
  317. package/templates/typeorm/src/users/users.service.ts +124 -0
  318. package/templates/typeorm/test/auth.e2e-spec.ts +111 -0
  319. package/templates/typeorm/test/session-auth.e2e-spec.ts +159 -0
  320. package/templates/typeorm/test/users.e2e-spec.ts +183 -0
  321. package/templates/typeorm/test/utils/clean-database.ts +65 -0
  322. package/templates/typeorm/test/utils/e2e-setup.ts +77 -0
  323. package/templates/typeorm/tsconfig.build.json +4 -0
  324. package/templates/typeorm/tsconfig.json +25 -0
  325. package/templates/typeorm/vitest.config.ts +20 -0
  326. package/templates/typeorm/vitest.e2e.config.ts +19 -0
@@ -0,0 +1,301 @@
1
+ import {
2
+ beforeEach,
3
+ describe,
4
+ expect,
5
+ it,
6
+ vi,
7
+ } from 'vitest';
8
+ import {
9
+ ConflictException,
10
+ NotFoundException,
11
+ } from '@nestjs/common';
12
+ import { instanceToPlain } from 'class-transformer';
13
+ import { Role } from '../common/constants/role.enum';
14
+ import type { DrizzleDatabase } from '../database/database.types';
15
+ import { UsersService } from './users.service';
16
+ import { UserEntity } from './entities/user.entity';
17
+
18
+ function createSelectBuilder<T>(result: T[]) {
19
+ const builder: any = {};
20
+
21
+ builder.from = vi.fn(() => builder);
22
+ builder.where = vi.fn(() => builder);
23
+ builder.orderBy = vi.fn(() => builder);
24
+ builder.limit = vi.fn(() => builder);
25
+ builder.offset = vi.fn(() => builder);
26
+
27
+ builder.then = (
28
+ resolve: (value: T[]) => unknown,
29
+ reject?: (reason: unknown) => unknown,
30
+ ) => Promise.resolve(result).then(resolve, reject);
31
+
32
+ return builder;
33
+ }
34
+
35
+ describe('UsersService', () => {
36
+ let usersService: UsersService;
37
+ let database: any;
38
+ let insertValues: ReturnType<typeof vi.fn>;
39
+ let updateSet: ReturnType<typeof vi.fn>;
40
+ let updateWhere: ReturnType<typeof vi.fn>;
41
+ let deleteWhere: ReturnType<typeof vi.fn>;
42
+ let mockUser: UserEntity;
43
+
44
+ beforeEach(() => {
45
+ mockUser = new UserEntity({
46
+ id: 'user-1',
47
+ name: 'Jeiel',
48
+ email: 'jeiel@example.com',
49
+ passwordHash: 'hash-secreto',
50
+ role: Role.USER,
51
+ avatarUrl: null,
52
+ emailVerifiedAt: null,
53
+ createdAt: new Date(),
54
+ updatedAt: new Date(),
55
+ });
56
+
57
+ insertValues = vi.fn().mockResolvedValue(undefined);
58
+
59
+ updateWhere = vi.fn().mockResolvedValue(undefined);
60
+ updateSet = vi.fn(() => ({
61
+ where: updateWhere,
62
+ }));
63
+
64
+ deleteWhere = vi.fn().mockResolvedValue(undefined);
65
+
66
+ database = {
67
+ select: vi.fn(),
68
+ insert: vi.fn(() => ({
69
+ values: insertValues,
70
+ })),
71
+ update: vi.fn(() => ({
72
+ set: updateSet,
73
+ })),
74
+ delete: vi.fn(() => ({
75
+ where: deleteWhere,
76
+ })),
77
+ };
78
+
79
+ usersService = new UsersService(
80
+ database as unknown as DrizzleDatabase,
81
+ );
82
+ });
83
+
84
+ it('deve lançar ConflictException se o e-mail já existir ao criar', async () => {
85
+ database.select.mockReturnValueOnce(
86
+ createSelectBuilder([
87
+ {
88
+ id: mockUser.id,
89
+ },
90
+ ]),
91
+ );
92
+
93
+ await expect(
94
+ usersService.create({
95
+ name: 'Jeiel',
96
+ email: 'jeiel@example.com',
97
+ password: 'senhaForte123',
98
+ }),
99
+ ).rejects.toBeInstanceOf(ConflictException);
100
+
101
+ expect(database.insert).not.toHaveBeenCalled();
102
+ });
103
+
104
+ it('deve criar um usuário e esconder o passwordHash na serialização', async () => {
105
+ database.select
106
+ .mockReturnValueOnce(createSelectBuilder([]))
107
+ .mockReturnValueOnce(
108
+ createSelectBuilder([mockUser]),
109
+ );
110
+
111
+ const result = await usersService.create({
112
+ name: 'Jeiel',
113
+ email: 'jeiel@example.com',
114
+ password: 'senhaForte123',
115
+ });
116
+
117
+ expect(result.email).toBe(
118
+ 'jeiel@example.com',
119
+ );
120
+
121
+ expect(
122
+ instanceToPlain(result),
123
+ ).not.toHaveProperty('passwordHash');
124
+
125
+ expect(database.insert).toHaveBeenCalled();
126
+ expect(insertValues).toHaveBeenCalledWith(
127
+ expect.objectContaining({
128
+ name: 'Jeiel',
129
+ email: 'jeiel@example.com',
130
+ role: Role.USER,
131
+ passwordHash: expect.any(String),
132
+ }),
133
+ );
134
+ });
135
+
136
+ it('deve lançar NotFoundException se o usuário não existir', async () => {
137
+ database.select.mockReturnValueOnce(
138
+ createSelectBuilder([]),
139
+ );
140
+
141
+ await expect(
142
+ usersService.findOne('id-invalido'),
143
+ ).rejects.toBeInstanceOf(NotFoundException);
144
+ });
145
+
146
+ it('deve retornar dados paginados em findAll', async () => {
147
+ const usersBuilder = createSelectBuilder([
148
+ mockUser,
149
+ ]);
150
+
151
+ const countBuilder = createSelectBuilder([
152
+ {
153
+ value: 1,
154
+ },
155
+ ]);
156
+
157
+ database.select
158
+ .mockReturnValueOnce(usersBuilder)
159
+ .mockReturnValueOnce(countBuilder);
160
+
161
+ const result = await usersService.findAll({
162
+ page: 1,
163
+ limit: 10,
164
+ });
165
+
166
+ expect(result.meta).toEqual({
167
+ total: 1,
168
+ page: 1,
169
+ limit: 10,
170
+ totalPages: 1,
171
+ });
172
+
173
+ expect(result.data).toHaveLength(1);
174
+ expect(usersBuilder.offset).toHaveBeenCalledWith(
175
+ 0,
176
+ );
177
+ expect(usersBuilder.limit).toHaveBeenCalledWith(
178
+ 10,
179
+ );
180
+ });
181
+
182
+ it('deve aplicar busca e filtro por role em findAll', async () => {
183
+ const usersBuilder = createSelectBuilder([
184
+ mockUser,
185
+ ]);
186
+
187
+ const countBuilder = createSelectBuilder([
188
+ {
189
+ value: 1,
190
+ },
191
+ ]);
192
+
193
+ database.select
194
+ .mockReturnValueOnce(usersBuilder)
195
+ .mockReturnValueOnce(countBuilder);
196
+
197
+ await usersService.findAll({
198
+ page: 1,
199
+ limit: 10,
200
+ search: 'jeiel',
201
+ role: Role.USER,
202
+ });
203
+
204
+ expect(
205
+ usersBuilder.where,
206
+ ).toHaveBeenCalledWith(
207
+ expect.anything(),
208
+ );
209
+
210
+ expect(
211
+ countBuilder.where,
212
+ ).toHaveBeenCalledWith(
213
+ expect.anything(),
214
+ );
215
+ });
216
+
217
+ it('deve atualizar um usuário existente', async () => {
218
+ const updatedUser = new UserEntity({
219
+ ...mockUser,
220
+ name: 'Novo Nome',
221
+ updatedAt: new Date(),
222
+ });
223
+
224
+ database.select
225
+ .mockReturnValueOnce(
226
+ createSelectBuilder([mockUser]),
227
+ )
228
+ .mockReturnValueOnce(
229
+ createSelectBuilder([updatedUser]),
230
+ );
231
+
232
+ const result = await usersService.update(
233
+ 'user-1',
234
+ {
235
+ name: 'Novo Nome',
236
+ },
237
+ );
238
+
239
+ expect(result.name).toBe('Novo Nome');
240
+
241
+ expect(updateSet).toHaveBeenCalledWith(
242
+ expect.objectContaining({
243
+ name: 'Novo Nome',
244
+ updatedAt: expect.any(Date),
245
+ }),
246
+ );
247
+
248
+ expect(updateWhere).toHaveBeenCalled();
249
+ });
250
+
251
+ it('deve remover um usuário existente', async () => {
252
+ database.select.mockReturnValueOnce(
253
+ createSelectBuilder([mockUser]),
254
+ );
255
+
256
+ const result = await usersService.remove(
257
+ 'user-1',
258
+ );
259
+
260
+ expect(database.delete).toHaveBeenCalled();
261
+ expect(deleteWhere).toHaveBeenCalled();
262
+
263
+ expect(result).toEqual({
264
+ message: 'Usuário removido com sucesso',
265
+ });
266
+ });
267
+
268
+ it('deve atualizar o avatar de um usuário', async () => {
269
+ const updatedUser = new UserEntity({
270
+ ...mockUser,
271
+ avatarUrl: '/uploads/avatars/x.png',
272
+ updatedAt: new Date(),
273
+ });
274
+
275
+ database.select
276
+ .mockReturnValueOnce(
277
+ createSelectBuilder([mockUser]),
278
+ )
279
+ .mockReturnValueOnce(
280
+ createSelectBuilder([updatedUser]),
281
+ );
282
+
283
+ const result = await usersService.updateAvatar(
284
+ 'user-1',
285
+ '/uploads/avatars/x.png',
286
+ );
287
+
288
+ expect(result.avatarUrl).toBe(
289
+ '/uploads/avatars/x.png',
290
+ );
291
+
292
+ expect(updateSet).toHaveBeenCalledWith(
293
+ expect.objectContaining({
294
+ avatarUrl: '/uploads/avatars/x.png',
295
+ updatedAt: expect.any(Date),
296
+ }),
297
+ );
298
+
299
+ expect(updateWhere).toHaveBeenCalled();
300
+ });
301
+ });
@@ -0,0 +1,213 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import {
3
+ ConflictException,
4
+ Injectable,
5
+ NotFoundException,
6
+ } from '@nestjs/common';
7
+ import {
8
+ and,
9
+ count,
10
+ desc,
11
+ eq,
12
+ or,
13
+ sql,
14
+ type SQL,
15
+ } from 'drizzle-orm';
16
+ import * as bcrypt from 'bcryptjs';
17
+ import { InjectDatabase } from '../database/database.decorators';
18
+ import type { DrizzleDatabase } from '../database/database.types';
19
+ import {
20
+ users,
21
+ type NewUser,
22
+ } from '../database/schema';
23
+ import { Role } from '../common/constants/role.enum';
24
+ import { CreateUserDto } from './dto/create-user.dto';
25
+ import { UpdateUserDto } from './dto/update-user.dto';
26
+ import { FindUsersQueryDto } from './dto/find-users-query.dto';
27
+ import { UserEntity } from './entities/user.entity';
28
+
29
+ @Injectable()
30
+ export class UsersService {
31
+ constructor(
32
+ @InjectDatabase()
33
+ private readonly database: DrizzleDatabase,
34
+ ) { }
35
+
36
+ async create(
37
+ dto: CreateUserDto,
38
+ ): Promise<UserEntity> {
39
+ const [existing] = await this.database
40
+ .select({ id: users.id })
41
+ .from(users)
42
+ .where(eq(users.email, dto.email))
43
+ .limit(1);
44
+
45
+ if (existing) {
46
+ throw new ConflictException(
47
+ 'E-mail já cadastrado',
48
+ );
49
+ }
50
+
51
+ const id = randomUUID();
52
+ const passwordHash = await bcrypt.hash(
53
+ dto.password,
54
+ 10,
55
+ );
56
+
57
+ await this.database.insert(users).values({
58
+ id,
59
+ name: dto.name,
60
+ email: dto.email,
61
+ passwordHash,
62
+ role: dto.role ?? Role.USER,
63
+ });
64
+
65
+ return this.findOne(id);
66
+ }
67
+
68
+ async findAll(query: FindUsersQueryDto) {
69
+ const {
70
+ page = 1,
71
+ limit = 10,
72
+ search,
73
+ role,
74
+ } = query;
75
+
76
+ const filters: SQL[] = [];
77
+
78
+ if (role) {
79
+ filters.push(eq(users.role, role));
80
+ }
81
+
82
+ if (search) {
83
+ const searchValue = `%${search}%`;
84
+
85
+ const searchCondition = or(
86
+ sql<boolean>`
87
+ lower(${users.name})
88
+ like lower(${searchValue})
89
+ `,
90
+ sql<boolean>`
91
+ lower(${users.email})
92
+ like lower(${searchValue})
93
+ `,
94
+ );
95
+
96
+ if (searchCondition) {
97
+ filters.push(searchCondition);
98
+ }
99
+ }
100
+
101
+ const where =
102
+ filters.length > 0
103
+ ? and(...filters)
104
+ : undefined;
105
+
106
+ const [data, totalResult] = await Promise.all([
107
+ this.database
108
+ .select()
109
+ .from(users)
110
+ .where(where)
111
+ .orderBy(desc(users.createdAt))
112
+ .limit(limit)
113
+ .offset((page - 1) * limit),
114
+
115
+ this.database
116
+ .select({
117
+ value: count(),
118
+ })
119
+ .from(users)
120
+ .where(where),
121
+ ]);
122
+
123
+ const total = totalResult[0]?.value ?? 0;
124
+
125
+ return {
126
+ data: data.map(
127
+ (user) => new UserEntity(user),
128
+ ),
129
+ meta: {
130
+ total,
131
+ page,
132
+ limit,
133
+ totalPages: Math.ceil(total / limit),
134
+ },
135
+ };
136
+ }
137
+
138
+ async findOne(id: string): Promise<UserEntity> {
139
+ const [user] = await this.database
140
+ .select()
141
+ .from(users)
142
+ .where(eq(users.id, id))
143
+ .limit(1);
144
+
145
+ if (!user) {
146
+ throw new NotFoundException(
147
+ 'Usuário não encontrado',
148
+ );
149
+ }
150
+
151
+ return new UserEntity(user);
152
+ }
153
+
154
+ async update(
155
+ id: string,
156
+ dto: UpdateUserDto,
157
+ ): Promise<UserEntity> {
158
+ await this.findOne(id);
159
+
160
+ const {
161
+ password,
162
+ ...updateFields
163
+ } = dto;
164
+
165
+ const data: Partial<NewUser> = {
166
+ ...updateFields,
167
+ updatedAt: new Date(),
168
+ };
169
+
170
+ if (password) {
171
+ data.passwordHash = await bcrypt.hash(
172
+ password,
173
+ 10,
174
+ );
175
+ }
176
+
177
+ await this.database
178
+ .update(users)
179
+ .set(data)
180
+ .where(eq(users.id, id));
181
+
182
+ return this.findOne(id);
183
+ }
184
+
185
+ async remove(id: string) {
186
+ await this.findOne(id);
187
+
188
+ await this.database
189
+ .delete(users)
190
+ .where(eq(users.id, id));
191
+
192
+ return {
193
+ message: 'Usuário removido com sucesso',
194
+ };
195
+ }
196
+
197
+ async updateAvatar(
198
+ id: string,
199
+ avatarUrl: string,
200
+ ): Promise<UserEntity> {
201
+ await this.findOne(id);
202
+
203
+ await this.database
204
+ .update(users)
205
+ .set({
206
+ avatarUrl,
207
+ updatedAt: new Date(),
208
+ })
209
+ .where(eq(users.id, id));
210
+
211
+ return this.findOne(id);
212
+ }
213
+ }
@@ -0,0 +1,114 @@
1
+ // nestforge:feature-file:auth:password,auth:token
2
+ import { INestApplication } from '@nestjs/common';
3
+ import { DRIZZLE_DATABASE } from '../src/database/database.constants';
4
+ import type { DrizzleDatabase } from '../src/database/database.types';
5
+ import request from 'supertest';
6
+ import { createTestApp } from './utils/e2e-setup';
7
+ import { cleanDatabase } from './utils/clean-database';
8
+
9
+ describe('Auth (e2e)', () => {
10
+ let app: INestApplication;
11
+ let database: DrizzleDatabase;
12
+
13
+ beforeAll(async () => {
14
+ app = await createTestApp();
15
+ database = app.get<DrizzleDatabase>(
16
+ DRIZZLE_DATABASE,
17
+ );
18
+ });
19
+
20
+ beforeEach(async () => {
21
+ await cleanDatabase(database);
22
+ });
23
+
24
+ afterAll(async () => {
25
+ await app.close();
26
+ });
27
+
28
+ it('deve registrar, logar, renovar e revogar o token', async () => {
29
+ const server = app.getHttpServer();
30
+
31
+ const registerResponse = await request(server)
32
+ .post('/auth/register')
33
+ .send({
34
+ name: 'Jeiel',
35
+ email: 'jeiel.e2e@example.com',
36
+ password: 'senhaForte123',
37
+ })
38
+ .expect(201);
39
+
40
+ expect(registerResponse.body).toHaveProperty(
41
+ 'accessToken',
42
+ );
43
+
44
+ expect(registerResponse.body).toHaveProperty(
45
+ 'refreshToken',
46
+ );
47
+
48
+ const loginResponse = await request(server)
49
+ .post('/auth/login')
50
+ .send({
51
+ email: 'jeiel.e2e@example.com',
52
+ password: 'senhaForte123',
53
+ })
54
+ .expect(200);
55
+
56
+ const refreshResponse = await request(server)
57
+ .post('/auth/refresh')
58
+ .send({
59
+ refreshToken:
60
+ loginResponse.body.refreshToken,
61
+ })
62
+ .expect(200);
63
+
64
+ expect(refreshResponse.body).toHaveProperty(
65
+ 'accessToken',
66
+ );
67
+
68
+ await request(server)
69
+ .post('/auth/logout')
70
+ .send({
71
+ refreshToken:
72
+ refreshResponse.body.refreshToken,
73
+ })
74
+ .expect(200);
75
+
76
+ await request(server)
77
+ .post('/auth/refresh')
78
+ .send({
79
+ refreshToken:
80
+ refreshResponse.body.refreshToken,
81
+ })
82
+ .expect(401);
83
+ });
84
+
85
+ it('não deve permitir cadastro com e-mail duplicado', async () => {
86
+ const server = app.getHttpServer();
87
+
88
+ const payload = {
89
+ name: 'Jeiel',
90
+ email: 'duplicado.e2e@example.com',
91
+ password: 'senhaForte123',
92
+ };
93
+
94
+ await request(server)
95
+ .post('/auth/register')
96
+ .send(payload)
97
+ .expect(201);
98
+
99
+ await request(server)
100
+ .post('/auth/register')
101
+ .send(payload)
102
+ .expect(409);
103
+ });
104
+
105
+ it('deve rejeitar login com credenciais inválidas', async () => {
106
+ await request(app.getHttpServer())
107
+ .post('/auth/login')
108
+ .send({
109
+ email: 'naoexiste.e2e@example.com',
110
+ password: 'qualquerSenha123',
111
+ })
112
+ .expect(401);
113
+ });
114
+ });