@koalarx/nest 1.19.0 → 3.0.1

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 (311) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +5 -37
  3. package/src/core/backgroud-services/cron-service/cron-job.handler.base.ts +66 -0
  4. package/src/core/backgroud-services/cron-service/cron-job.handler.spec.ts +38 -0
  5. package/src/core/backgroud-services/event-service/event-class.ts +5 -0
  6. package/src/core/backgroud-services/event-service/event-handler.base.ts +17 -0
  7. package/src/core/backgroud-services/event-service/event-is-trigger.ts +3 -0
  8. package/src/core/backgroud-services/event-service/event-job.ts +28 -0
  9. package/src/core/backgroud-services/event-service/event-queue.spec.ts +47 -0
  10. package/src/core/backgroud-services/event-service/event-queue.ts +107 -0
  11. package/src/core/constants/query-params.ts +7 -0
  12. package/src/core/controllers/base.controller.ts +9 -0
  13. package/src/core/controllers/controller.decorator.ts +10 -0
  14. package/src/core/controllers/created-registre-response.base.ts +17 -0
  15. package/src/core/controllers/list-response.base.ts +8 -0
  16. package/src/core/controllers/pagination.request.ts +41 -0
  17. package/src/core/controllers/router-config.base.ts +14 -0
  18. package/src/core/controllers/schemas/boolean.schema.ts +10 -0
  19. package/src/core/controllers/schemas/document-number.schema.ts +23 -0
  20. package/src/core/controllers/schemas/email.schema.ts +13 -0
  21. package/src/core/controllers/schemas/list-query.schema.ts +17 -0
  22. package/src/core/controllers/schemas/native-enum.schema.ts +34 -0
  23. package/src/core/controllers/schemas/set-mask-document-number.schema.ts +13 -0
  24. package/src/core/database/entity.base.ts +95 -0
  25. package/src/core/database/entity.decorator.spec.ts +71 -0
  26. package/src/core/database/entity.decorator.ts +39 -0
  27. package/src/core/database/prisma-client-with-custom-transaction.interface.ts +13 -0
  28. package/src/core/database/prisma-resolver.ts +99 -0
  29. package/src/core/database/prisma-transactional-client.ts +43 -0
  30. package/src/core/database/prisma.service.ts +136 -0
  31. package/src/core/database/repository.base.ts +548 -0
  32. package/src/core/dtos/pagination.dto.ts +35 -0
  33. package/src/core/errors/bad-request.error.ts +8 -0
  34. package/src/core/errors/conflict.error.ts +7 -0
  35. package/src/core/errors/error.base.ts +5 -0
  36. package/src/core/errors/no-content.error.ts +8 -0
  37. package/src/core/errors/not-allowed.error.ts +8 -0
  38. package/src/core/errors/resource-not-found.error.ts +8 -0
  39. package/{core/errors/use-case-error.d.ts → src/core/errors/use-case-error.ts} +1 -1
  40. package/src/core/errors/user-already-exist.error.ts +7 -0
  41. package/src/core/errors/wrong-credentials.error.ts +7 -0
  42. package/src/core/health-check/health-check.controller.ts +13 -0
  43. package/src/core/health-check/health-check.module.ts +7 -0
  44. package/src/core/index.ts +56 -0
  45. package/src/core/koala-app.ts +379 -0
  46. package/src/core/koala-global-vars.ts +8 -0
  47. package/src/core/koala-nest-database.module.ts +65 -0
  48. package/src/core/koala-nest-http.module.ts +44 -0
  49. package/src/core/koala-nest.module.ts +67 -0
  50. package/src/core/mapping/auto-mapping-class-context.ts +28 -0
  51. package/src/core/mapping/auto-mapping-context.ts +26 -0
  52. package/src/core/mapping/auto-mapping-list.ts +154 -0
  53. package/src/core/mapping/auto-mapping-profile.ts +3 -0
  54. package/src/core/mapping/auto-mapping.decorator.ts +54 -0
  55. package/src/core/mapping/auto-mapping.module.ts +17 -0
  56. package/src/core/mapping/auto-mapping.service.ts +187 -0
  57. package/src/core/mapping/create-map.ts +11 -0
  58. package/src/core/mapping/for-member.ts +16 -0
  59. package/src/core/request-overflow/request-handler.base.ts +8 -0
  60. package/src/core/request-overflow/request-result.spec.ts +23 -0
  61. package/src/core/request-overflow/request-result.ts +41 -0
  62. package/src/core/request-overflow/request-validator.base.ts +33 -0
  63. package/src/core/security/strategies/api-key.strategy.ts +45 -0
  64. package/src/core/utils/assing-object.ts +9 -0
  65. package/src/core/utils/env.config.ts +17 -0
  66. package/src/core/utils/filter-request-params.ts +23 -0
  67. package/src/core/utils/find-on-list.ts +18 -0
  68. package/src/core/utils/get-type-by-prop.ts +9 -0
  69. package/src/core/utils/instanciate-class-with-dependencies-injection.ts +12 -0
  70. package/src/core/utils/interfaces/icomparable.ts +6 -0
  71. package/src/core/utils/list.spec.ts +81 -0
  72. package/src/core/utils/list.ts +223 -0
  73. package/src/core/utils/promise-all.ts +24 -0
  74. package/src/core/utils/set-mask-document-number.ts +13 -0
  75. package/src/core/validators/file-validator.ts +113 -0
  76. package/src/decorators/api-exclude-endpoint-diff-develop.decorator.ts +15 -0
  77. package/src/decorators/api-property-enum.decorator.ts +58 -0
  78. package/src/decorators/api-property-only-develop.decorator.ts +6 -0
  79. package/src/decorators/cookies.decorator.ts +8 -0
  80. package/src/decorators/is-public.decorator.ts +5 -0
  81. package/src/decorators/upload.decorator.ts +31 -0
  82. package/src/env/env.module.ts +8 -0
  83. package/src/env/env.service.ts +12 -0
  84. package/src/env/env.ts +14 -0
  85. package/src/filters/domain-errors.filter.ts +97 -0
  86. package/src/filters/global-exception.filter.ts +60 -0
  87. package/src/filters/prisma-validation-exception.filter.ts +73 -0
  88. package/src/filters/zod-errors.filter.ts +48 -0
  89. package/src/services/logging/ilogging.service.ts +17 -0
  90. package/src/services/logging/logging.service.ts +10 -0
  91. package/src/services/redis/iredis.service.ts +11 -0
  92. package/src/services/redis/redis.service.ts +70 -0
  93. package/src/services/redlock/ired-lock.service.ts +4 -0
  94. package/src/services/redlock/red-lock.service.ts +36 -0
  95. package/src/test/koala-app-test-dependencies.ts +15 -0
  96. package/src/test/koala-app-test.ts +103 -0
  97. package/src/test/repositories/in-memory-base.repository.ts +90 -0
  98. package/src/test/services/fake-logging.service.ts +7 -0
  99. package/src/test/services/fake-red-lock.service.ts +11 -0
  100. package/src/test/utils/create-e2e-database.ts +55 -0
  101. package/src/test/utils/drop-e2e-database.ts +36 -0
  102. package/src/test/utils/wait-for.ts +31 -0
  103. package/tsconfig.lib.json +11 -0
  104. package/LICENSE +0 -21
  105. package/README.md +0 -499
  106. package/core/backgroud-services/cron-service/cron-job.handler.base.d.ts +0 -16
  107. package/core/backgroud-services/cron-service/cron-job.handler.base.js +0 -49
  108. package/core/backgroud-services/event-service/event-class.d.ts +0 -5
  109. package/core/backgroud-services/event-service/event-class.js +0 -11
  110. package/core/backgroud-services/event-service/event-handler.base.d.ts +0 -8
  111. package/core/backgroud-services/event-service/event-handler.base.js +0 -14
  112. package/core/backgroud-services/event-service/event-is-trigger.d.ts +0 -3
  113. package/core/backgroud-services/event-service/event-is-trigger.js +0 -7
  114. package/core/backgroud-services/event-service/event-job.d.ts +0 -13
  115. package/core/backgroud-services/event-service/event-job.js +0 -21
  116. package/core/backgroud-services/event-service/event-queue.d.ts +0 -17
  117. package/core/backgroud-services/event-service/event-queue.js +0 -62
  118. package/core/constants/query-params.d.ts +0 -6
  119. package/core/constants/query-params.js +0 -8
  120. package/core/controllers/base.controller.d.ts +0 -4
  121. package/core/controllers/base.controller.js +0 -6
  122. package/core/controllers/controller.decorator.d.ts +0 -2
  123. package/core/controllers/controller.decorator.js +0 -11
  124. package/core/controllers/created-registre-response.base.d.ts +0 -10
  125. package/core/controllers/created-registre-response.base.js +0 -35
  126. package/core/controllers/list-response.base.d.ts +0 -4
  127. package/core/controllers/list-response.base.js +0 -21
  128. package/core/controllers/pagination.request.d.ts +0 -10
  129. package/core/controllers/pagination.request.js +0 -56
  130. package/core/controllers/router-config.base.d.ts +0 -7
  131. package/core/controllers/router-config.base.js +0 -18
  132. package/core/controllers/schemas/boolean.schema.d.ts +0 -2
  133. package/core/controllers/schemas/boolean.schema.js +0 -12
  134. package/core/controllers/schemas/document-number.schema.d.ts +0 -1
  135. package/core/controllers/schemas/document-number.schema.js +0 -26
  136. package/core/controllers/schemas/email.schema.d.ts +0 -1
  137. package/core/controllers/schemas/email.schema.js +0 -13
  138. package/core/controllers/schemas/list-query.schema.d.ts +0 -17
  139. package/core/controllers/schemas/list-query.schema.js +0 -19
  140. package/core/controllers/schemas/native-enum.schema.d.ts +0 -7
  141. package/core/controllers/schemas/native-enum.schema.js +0 -28
  142. package/core/controllers/schemas/set-mask-document-number.schema.d.ts +0 -1
  143. package/core/controllers/schemas/set-mask-document-number.schema.js +0 -13
  144. package/core/database/entity.base.d.ts +0 -20
  145. package/core/database/entity.base.js +0 -71
  146. package/core/database/entity.decorator.d.ts +0 -13
  147. package/core/database/entity.decorator.js +0 -23
  148. package/core/database/prisma-client-with-custom-transaction.interface.d.ts +0 -8
  149. package/core/database/prisma-client-with-custom-transaction.interface.js +0 -2
  150. package/core/database/prisma-resolver.d.ts +0 -2
  151. package/core/database/prisma-resolver.js +0 -74
  152. package/core/database/prisma-transactional-client.d.ts +0 -11
  153. package/core/database/prisma-transactional-client.js +0 -25
  154. package/core/database/prisma.service.d.ts +0 -24
  155. package/core/database/prisma.service.js +0 -104
  156. package/core/database/repository.base.d.ts +0 -44
  157. package/core/database/repository.base.js +0 -360
  158. package/core/dtos/pagination.dto.d.ts +0 -9
  159. package/core/dtos/pagination.dto.js +0 -49
  160. package/core/errors/bad-request.error.d.ts +0 -5
  161. package/core/errors/bad-request.error.js +0 -10
  162. package/core/errors/conflict.error.d.ts +0 -4
  163. package/core/errors/conflict.error.js +0 -10
  164. package/core/errors/error.base.d.ts +0 -4
  165. package/core/errors/error.base.js +0 -11
  166. package/core/errors/no-content.error.d.ts +0 -5
  167. package/core/errors/no-content.error.js +0 -10
  168. package/core/errors/not-allowed.error.d.ts +0 -5
  169. package/core/errors/not-allowed.error.js +0 -10
  170. package/core/errors/resource-not-found.error.d.ts +0 -5
  171. package/core/errors/resource-not-found.error.js +0 -10
  172. package/core/errors/use-case-error.js +0 -2
  173. package/core/errors/user-already-exist.error.d.ts +0 -4
  174. package/core/errors/user-already-exist.error.js +0 -10
  175. package/core/errors/wrong-credentials.error.d.ts +0 -4
  176. package/core/errors/wrong-credentials.error.js +0 -10
  177. package/core/health-check/health-check.controller.d.ts +0 -5
  178. package/core/health-check/health-check.controller.js +0 -32
  179. package/core/health-check/health-check.module.d.ts +0 -2
  180. package/core/health-check/health-check.module.js +0 -19
  181. package/core/index.d.ts +0 -18
  182. package/core/index.js +0 -7
  183. package/core/koala-app.d.ts +0 -64
  184. package/core/koala-app.js +0 -252
  185. package/core/koala-global-vars.d.ts +0 -7
  186. package/core/koala-global-vars.js +0 -9
  187. package/core/koala-nest-database.module.d.ts +0 -16
  188. package/core/koala-nest-database.module.js +0 -52
  189. package/core/koala-nest-http.module.d.ts +0 -13
  190. package/core/koala-nest-http.module.js +0 -37
  191. package/core/koala-nest.module.d.ts +0 -17
  192. package/core/koala-nest.module.js +0 -66
  193. package/core/mapping/auto-mapping-class-context.d.ts +0 -16
  194. package/core/mapping/auto-mapping-class-context.js +0 -18
  195. package/core/mapping/auto-mapping-context.d.ts +0 -11
  196. package/core/mapping/auto-mapping-context.js +0 -24
  197. package/core/mapping/auto-mapping-list.d.ts +0 -27
  198. package/core/mapping/auto-mapping-list.js +0 -94
  199. package/core/mapping/auto-mapping-profile.d.ts +0 -3
  200. package/core/mapping/auto-mapping-profile.js +0 -6
  201. package/core/mapping/auto-mapping.decorator.d.ts +0 -9
  202. package/core/mapping/auto-mapping.decorator.js +0 -27
  203. package/core/mapping/auto-mapping.module.d.ts +0 -5
  204. package/core/mapping/auto-mapping.module.js +0 -29
  205. package/core/mapping/auto-mapping.service.d.ts +0 -14
  206. package/core/mapping/auto-mapping.service.js +0 -140
  207. package/core/mapping/create-map.d.ts +0 -3
  208. package/core/mapping/create-map.js +0 -7
  209. package/core/mapping/for-member.d.ts +0 -5
  210. package/core/mapping/for-member.js +0 -8
  211. package/core/request-overflow/request-handler.base.d.ts +0 -4
  212. package/core/request-overflow/request-handler.base.js +0 -6
  213. package/core/request-overflow/request-result.d.ts +0 -15
  214. package/core/request-overflow/request-result.js +0 -37
  215. package/core/request-overflow/request-validator.base.d.ts +0 -7
  216. package/core/request-overflow/request-validator.base.js +0 -26
  217. package/core/security/strategies/api-key.strategy.d.ts +0 -16
  218. package/core/security/strategies/api-key.strategy.js +0 -31
  219. package/core/utils/assing-object.d.ts +0 -5
  220. package/core/utils/assing-object.js +0 -6
  221. package/core/utils/env.config.d.ts +0 -6
  222. package/core/utils/env.config.js +0 -18
  223. package/core/utils/filter-request-params.d.ts +0 -13
  224. package/core/utils/filter-request-params.js +0 -22
  225. package/core/utils/find-on-list.d.ts +0 -2
  226. package/core/utils/find-on-list.js +0 -13
  227. package/core/utils/get-type-by-prop.d.ts +0 -2
  228. package/core/utils/get-type-by-prop.js +0 -11
  229. package/core/utils/instanciate-class-with-dependencies-injection.d.ts +0 -2
  230. package/core/utils/instanciate-class-with-dependencies-injection.js +0 -10
  231. package/core/utils/interfaces/icomparable.d.ts +0 -5
  232. package/core/utils/interfaces/icomparable.js +0 -6
  233. package/core/utils/list.d.ts +0 -39
  234. package/core/utils/list.js +0 -168
  235. package/core/utils/promise-all.d.ts +0 -7
  236. package/core/utils/promise-all.js +0 -19
  237. package/core/utils/set-mask-document-number.d.ts +0 -1
  238. package/core/utils/set-mask-document-number.js +0 -13
  239. package/core/validators/file-validator.d.ts +0 -27
  240. package/core/validators/file-validator.js +0 -94
  241. package/decorators/api-exclude-endpoint-diff-develop.decorator.d.ts +0 -1
  242. package/decorators/api-exclude-endpoint-diff-develop.decorator.js +0 -9
  243. package/decorators/api-property-enum.decorator.d.ts +0 -8
  244. package/decorators/api-property-enum.decorator.js +0 -21
  245. package/decorators/api-property-only-develop.decorator.d.ts +0 -2
  246. package/decorators/api-property-only-develop.decorator.js +0 -9
  247. package/decorators/cookies.decorator.d.ts +0 -1
  248. package/decorators/cookies.decorator.js +0 -8
  249. package/decorators/is-public.decorator.d.ts +0 -2
  250. package/decorators/is-public.decorator.js +0 -7
  251. package/decorators/upload.decorator.d.ts +0 -1
  252. package/decorators/upload.decorator.js +0 -18
  253. package/docs/00-cli-reference.md +0 -201
  254. package/docs/01-guia-instalacao.md +0 -113
  255. package/docs/02-configuracao-inicial.md +0 -176
  256. package/docs/04-tratamento-erros.md +0 -303
  257. package/docs/05-features-avancadas.md +0 -969
  258. package/docs/06-decoradores.md +0 -220
  259. package/docs/07-guia-bun.md +0 -176
  260. package/docs/08-prisma-client.md +0 -487
  261. package/docs/09-mcp-vscode-extension.md +0 -437
  262. package/docs/EXAMPLE.md +0 -1671
  263. package/docs/README.md +0 -59
  264. package/env/env.d.ts +0 -25
  265. package/env/env.js +0 -14
  266. package/env/env.module.d.ts +0 -2
  267. package/env/env.module.js +0 -20
  268. package/env/env.service.d.ts +0 -7
  269. package/env/env.service.js +0 -28
  270. package/filters/domain-errors.filter.d.ts +0 -18
  271. package/filters/domain-errors.filter.js +0 -92
  272. package/filters/global-exception.filter.d.ts +0 -8
  273. package/filters/global-exception.filter.js +0 -68
  274. package/filters/prisma-validation-exception.filter.d.ts +0 -10
  275. package/filters/prisma-validation-exception.filter.js +0 -82
  276. package/filters/zod-errors.filter.d.ts +0 -9
  277. package/filters/zod-errors.filter.js +0 -60
  278. package/mcp-server/mcp.json.example +0 -27
  279. package/mcp-server/server.d.ts +0 -2
  280. package/mcp-server/server.d.ts.map +0 -1
  281. package/mcp-server/server.js +0 -248
  282. package/mcp-server/server.js.map +0 -1
  283. package/services/logging/ilogging.service.d.ts +0 -16
  284. package/services/logging/ilogging.service.js +0 -6
  285. package/services/logging/logging.service.d.ts +0 -4
  286. package/services/logging/logging.service.js +0 -20
  287. package/services/redis/iredis.service.d.ts +0 -6
  288. package/services/redis/iredis.service.js +0 -6
  289. package/services/redis/redis.service.d.ts +0 -14
  290. package/services/redis/redis.service.js +0 -65
  291. package/services/redlock/ired-lock.service.d.ts +0 -4
  292. package/services/redlock/ired-lock.service.js +0 -6
  293. package/services/redlock/red-lock.service.d.ts +0 -9
  294. package/services/redlock/red-lock.service.js +0 -46
  295. package/test/koala-app-test-dependencies.d.ts +0 -10
  296. package/test/koala-app-test-dependencies.js +0 -13
  297. package/test/koala-app-test.d.ts +0 -22
  298. package/test/koala-app-test.js +0 -77
  299. package/test/repositories/in-memory-base.repository.d.ts +0 -17
  300. package/test/repositories/in-memory-base.repository.js +0 -65
  301. package/test/services/fake-logging.service.d.ts +0 -4
  302. package/test/services/fake-logging.service.js +0 -9
  303. package/test/services/fake-red-lock.service.d.ts +0 -5
  304. package/test/services/fake-red-lock.service.js +0 -11
  305. package/test/utils/create-e2e-database.d.ts +0 -2
  306. package/test/utils/create-e2e-database.js +0 -47
  307. package/test/utils/drop-e2e-database.d.ts +0 -2
  308. package/test/utils/drop-e2e-database.js +0 -33
  309. package/test/utils/wait-for.d.ts +0 -1
  310. package/test/utils/wait-for.js +0 -21
  311. package/tsconfig.lib.tsbuildinfo +0 -1
@@ -0,0 +1,97 @@
1
+ import { ArgumentsHost, Catch, HttpStatus } from '@nestjs/common'
2
+ import { BaseExceptionFilter } from '@nestjs/core'
3
+ import { BadRequestError } from '../core/errors/bad-request.error'
4
+ import { ConflictError } from '../core/errors/conflict.error'
5
+ import { NoContentError } from '../core/errors/no-content.error'
6
+ import { NotAllowedError } from '../core/errors/not-allowed.error'
7
+ import { ResourceNotFoundError } from '../core/errors/resource-not-found.error'
8
+ import { UserAlreadyExist } from '../core/errors/user-already-exist.error'
9
+ import { WrongCredentialsError } from '../core/errors/wrong-credentials.error'
10
+ import { KoalaGlobalVars } from '../core/koala-global-vars'
11
+ import { EnvConfig } from '../core/utils/env.config'
12
+ import { FilterRequestParams } from '../core/utils/filter-request-params'
13
+ import { ILoggingService } from '../services/logging/ilogging.service'
14
+
15
+ type DomainErrors =
16
+ | NotAllowedError
17
+ | ResourceNotFoundError
18
+ | UserAlreadyExist
19
+ | WrongCredentialsError
20
+ | ConflictError
21
+ | BadRequestError
22
+ | NoContentError
23
+
24
+ @Catch(
25
+ NotAllowedError,
26
+ ResourceNotFoundError,
27
+ UserAlreadyExist,
28
+ WrongCredentialsError,
29
+ ConflictError,
30
+ BadRequestError,
31
+ NoContentError,
32
+ )
33
+ export class DomainErrorsFilter extends BaseExceptionFilter {
34
+ constructor(private readonly loggingService: ILoggingService) {
35
+ super()
36
+ }
37
+
38
+ public catch(exception: DomainErrors, host: ArgumentsHost) {
39
+ const mappedException = this.map(exception)
40
+ const filterRequestParams = FilterRequestParams.get(host)
41
+
42
+ if (mappedException.statusCode !== HttpStatus.UNAUTHORIZED) {
43
+ if (!EnvConfig.isEnvTest) {
44
+ this.loggingService
45
+ .report({
46
+ error: exception,
47
+ packageName: KoalaGlobalVars.appName,
48
+ loggedUsername: filterRequestParams.loggedUserName,
49
+ httpRequest: {
50
+ ...filterRequestParams.filterParams,
51
+ statusCode: mappedException.statusCode,
52
+ response: mappedException,
53
+ },
54
+ })
55
+ .catch((err) => console.error(err))
56
+ } else {
57
+ console.error(exception)
58
+ }
59
+ }
60
+
61
+ return filterRequestParams.response
62
+ .status(mappedException.statusCode)
63
+ .json(mappedException)
64
+ }
65
+
66
+ private map(exception: DomainErrors) {
67
+ const mappedException = {
68
+ statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
69
+ message: exception.message,
70
+ data: exception.data,
71
+ }
72
+
73
+ switch (exception.constructor) {
74
+ case UserAlreadyExist:
75
+ case NotAllowedError:
76
+ case BadRequestError:
77
+ mappedException.statusCode = HttpStatus.BAD_REQUEST
78
+ break
79
+ case ResourceNotFoundError:
80
+ mappedException.statusCode = HttpStatus.NOT_FOUND
81
+ break
82
+ case WrongCredentialsError:
83
+ mappedException.statusCode = HttpStatus.UNAUTHORIZED
84
+ break
85
+ case ConflictError:
86
+ mappedException.statusCode = HttpStatus.CONFLICT
87
+ break
88
+ case NoContentError:
89
+ mappedException.statusCode = HttpStatus.NO_CONTENT
90
+ break
91
+ default:
92
+ console.error(exception)
93
+ }
94
+
95
+ return mappedException
96
+ }
97
+ }
@@ -0,0 +1,60 @@
1
+ import { ArgumentsHost, Catch, HttpException, HttpStatus } from '@nestjs/common'
2
+ import { BaseExceptionFilter } from '@nestjs/core'
3
+ import { IncomingMessage } from 'node:http'
4
+ import { KoalaGlobalVars } from '../core/koala-global-vars'
5
+ import { EnvConfig } from '../core/utils/env.config'
6
+ import { FilterRequestParams } from '../core/utils/filter-request-params'
7
+ import { ILoggingService } from '../services/logging/ilogging.service'
8
+
9
+ @Catch()
10
+ export class GlobalExceptionsFilter extends BaseExceptionFilter {
11
+ constructor(private readonly loggingService: ILoggingService) {
12
+ super()
13
+ }
14
+
15
+ catch(exception: Error, host: ArgumentsHost) {
16
+ const filterRequestParams = FilterRequestParams.get(host)
17
+ const request: IncomingMessage | null =
18
+ host.getArgs().find((arg) => arg instanceof IncomingMessage) ?? null
19
+
20
+ const statusCode =
21
+ exception instanceof HttpException
22
+ ? exception.getStatus()
23
+ : HttpStatus.INTERNAL_SERVER_ERROR
24
+
25
+ const responseBody =
26
+ exception instanceof HttpException
27
+ ? exception.getResponse()
28
+ : {
29
+ statusCode,
30
+ timestamp: new Date().toISOString(),
31
+ path: filterRequestParams.filterParams.endpoint,
32
+ }
33
+
34
+ if (
35
+ !exception.message?.includes('Cannot GET /socket.io') &&
36
+ !exception.message?.includes('Cannot GET /favicon.ico') &&
37
+ !['/'].includes(request?.url ?? '') &&
38
+ statusCode !== HttpStatus.UNAUTHORIZED
39
+ ) {
40
+ if (!EnvConfig.isEnvTest) {
41
+ this.loggingService
42
+ .report({
43
+ error: exception,
44
+ packageName: KoalaGlobalVars.appName,
45
+ loggedUsername: filterRequestParams.loggedUserName,
46
+ httpRequest: {
47
+ ...filterRequestParams.filterParams,
48
+ statusCode,
49
+ response: responseBody as any,
50
+ },
51
+ })
52
+ .catch((err) => console.error(err))
53
+ } else {
54
+ console.error(exception)
55
+ }
56
+ }
57
+
58
+ return filterRequestParams.response.status(statusCode).json(responseBody)
59
+ }
60
+ }
@@ -0,0 +1,73 @@
1
+ import { ArgumentsHost, Catch, HttpStatus } from '@nestjs/common'
2
+ import { BaseExceptionFilter } from '@nestjs/core'
3
+ import { Prisma } from 'prisma/generated/client'
4
+ import { KoalaGlobalVars } from '../core/koala-global-vars'
5
+ import { EnvConfig } from '../core/utils/env.config'
6
+ import { FilterRequestParams } from '../core/utils/filter-request-params'
7
+ import { ILoggingService } from '../services/logging/ilogging.service'
8
+
9
+ @Catch(Prisma.PrismaClientKnownRequestError)
10
+ export class PrismaValidationExceptionFilter extends BaseExceptionFilter {
11
+ constructor(private readonly loggingService: ILoggingService) {
12
+ super()
13
+ }
14
+
15
+ public catch(
16
+ exception: Prisma.PrismaClientKnownRequestError,
17
+ host: ArgumentsHost,
18
+ ) {
19
+ const translatedResponse = this.translate(exception)
20
+ const filterRequestParams = FilterRequestParams.get(host)
21
+
22
+ if (translatedResponse.statusCode !== HttpStatus.UNAUTHORIZED) {
23
+ if (!EnvConfig.isEnvTest) {
24
+ this.loggingService
25
+ .report({
26
+ error: exception,
27
+ packageName: KoalaGlobalVars.appName,
28
+ loggedUsername: filterRequestParams.loggedUserName,
29
+ httpRequest: {
30
+ ...filterRequestParams.filterParams,
31
+ statusCode: translatedResponse.statusCode,
32
+ response: translatedResponse,
33
+ },
34
+ })
35
+ .catch((err) => console.error(err))
36
+ } else {
37
+ console.error(exception)
38
+ }
39
+ }
40
+
41
+ return filterRequestParams.response
42
+ .status(translatedResponse.statusCode)
43
+ .json(translatedResponse)
44
+ }
45
+
46
+ private translate(exception: Prisma.PrismaClientKnownRequestError) {
47
+ switch (exception.code) {
48
+ case 'P2002':
49
+ return {
50
+ statusCode: HttpStatus.CONFLICT,
51
+ message: 'Registro já existente.',
52
+ }
53
+ case 'P2003':
54
+ return {
55
+ statusCode: HttpStatus.BAD_REQUEST,
56
+ message:
57
+ 'Falha devido a relacionamento. Verifique se o relacionamento existe ou é valido.',
58
+ }
59
+ case 'P2025':
60
+ return {
61
+ statusCode: HttpStatus.NOT_FOUND,
62
+ message: 'Registro não encontrado.',
63
+ }
64
+ default:
65
+ console.error(exception)
66
+ return {
67
+ statusCode: HttpStatus.BAD_REQUEST,
68
+ message:
69
+ 'Ocorreu um erro desconhecido relacionado aos dados enviados.',
70
+ }
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,48 @@
1
+ import { ArgumentsHost, Catch, HttpStatus } from '@nestjs/common'
2
+ import { BaseExceptionFilter } from '@nestjs/core'
3
+ import { ZodError } from 'zod'
4
+ import { fromZodError } from 'zod-validation-error'
5
+ import { KoalaGlobalVars } from '../core/koala-global-vars'
6
+ import { EnvConfig } from '../core/utils/env.config'
7
+ import { FilterRequestParams } from '../core/utils/filter-request-params'
8
+ import { ILoggingService } from '../services/logging/ilogging.service'
9
+
10
+ @Catch(ZodError)
11
+ export class ZodErrorsFilter extends BaseExceptionFilter {
12
+ constructor(private readonly loggingService: ILoggingService) {
13
+ super()
14
+ }
15
+
16
+ public catch(exception: ZodError, host: ArgumentsHost) {
17
+ const filterRequestParams = FilterRequestParams.get(host)
18
+
19
+ const zodResponse = {
20
+ errors: fromZodError(exception).details.map(
21
+ (detail) => `${detail.path} ${detail.message.toLowerCase()}`,
22
+ ),
23
+ statusCode: HttpStatus.BAD_REQUEST,
24
+ message: 'Dados enviados inválidos',
25
+ }
26
+
27
+ if (!EnvConfig.isEnvTest) {
28
+ this.loggingService
29
+ .report({
30
+ error: exception,
31
+ packageName: KoalaGlobalVars.appName,
32
+ loggedUsername: filterRequestParams.loggedUserName,
33
+ httpRequest: {
34
+ ...filterRequestParams.filterParams,
35
+ statusCode: HttpStatus.BAD_REQUEST,
36
+ response: zodResponse,
37
+ },
38
+ })
39
+ .catch((err) => console.error(err))
40
+ } else {
41
+ console.error(exception)
42
+ }
43
+
44
+ return filterRequestParams.response
45
+ .status(HttpStatus.BAD_REQUEST)
46
+ .send(zodResponse)
47
+ }
48
+ }
@@ -0,0 +1,17 @@
1
+ export interface LoggingReportProps {
2
+ loggedUsername: string
3
+ packageName: string
4
+ error: Error
5
+ httpRequest?: {
6
+ method: string
7
+ endpoint: string
8
+ queryParams?: string
9
+ payload?: object
10
+ statusCode: number
11
+ response?: object
12
+ }
13
+ }
14
+
15
+ export abstract class ILoggingService {
16
+ abstract report(data: LoggingReportProps): Promise<void>
17
+ }
@@ -0,0 +1,10 @@
1
+ import { Injectable } from '@nestjs/common'
2
+ import { ILoggingService, LoggingReportProps } from './ilogging.service'
3
+ import consola from 'consola'
4
+
5
+ @Injectable()
6
+ export class LoggingService implements ILoggingService {
7
+ async report(data: LoggingReportProps): Promise<void> {
8
+ consola.error(data.error)
9
+ }
10
+ }
@@ -0,0 +1,11 @@
1
+ export abstract class IRedisService {
2
+ abstract isConnected: boolean
3
+ abstract getCache(key: string): Promise<string | null>
4
+ abstract setCache(
5
+ key: string,
6
+ ttlSecondsCache: number,
7
+ payload: any,
8
+ ): Promise<void>
9
+
10
+ abstract deleteCache(key: string): Promise<void>
11
+ }
@@ -0,0 +1,70 @@
1
+ import { Injectable, OnModuleDestroy } from '@nestjs/common'
2
+ import Redis from 'ioredis'
3
+ import { EnvConfig } from '../../core/utils/env.config'
4
+ import { EnvService } from '../../env/env.service'
5
+ import { IRedisService } from './iredis.service'
6
+
7
+ @Injectable()
8
+ export class RedisService implements IRedisService, OnModuleDestroy {
9
+ private readonly redisClient: Redis
10
+ private readonly environment: string
11
+
12
+ get isConnected(): boolean {
13
+ return !!this.redisClient
14
+ }
15
+
16
+ constructor(env: EnvService) {
17
+ if (!EnvConfig.isEnvTest) {
18
+ const redisUrl = env.get('REDIS_CONNECTION_STRING')
19
+
20
+ if (redisUrl) {
21
+ const url = new URL(redisUrl)
22
+ this.environment = env.get('NODE_ENV')
23
+
24
+ this.redisClient = new Redis({
25
+ host: url.hostname,
26
+ port: Number(url.port),
27
+ password: url.password,
28
+ username: url.username,
29
+ })
30
+ }
31
+ }
32
+ }
33
+
34
+ onModuleDestroy() {
35
+ this.redisClient.disconnect()
36
+ }
37
+
38
+ async getCache(key: string): Promise<string | null> {
39
+ if (EnvConfig.isEnvTest) {
40
+ return ''
41
+ }
42
+
43
+ return await this.redisClient.get(this.getKeyCache(key))
44
+ }
45
+
46
+ async setCache(
47
+ key: string,
48
+ ttlSecondsCache: number,
49
+ payload: any,
50
+ ): Promise<void> {
51
+ if (!EnvConfig.isEnvTest) {
52
+ await this.redisClient.set(
53
+ this.getKeyCache(key),
54
+ JSON.stringify(payload),
55
+ 'EX',
56
+ ttlSecondsCache,
57
+ )
58
+ }
59
+ }
60
+
61
+ async deleteCache(key: string): Promise<void> {
62
+ if (!EnvConfig.isEnvTest) {
63
+ await this.redisClient.del(this.getKeyCache(key))
64
+ }
65
+ }
66
+
67
+ private getKeyCache(key: string) {
68
+ return `${this.environment}:app:${key}`
69
+ }
70
+ }
@@ -0,0 +1,4 @@
1
+ export abstract class IRedLockService {
2
+ abstract acquiredLock(key: string, ttlSecondsLock: number): Promise<boolean>
3
+ abstract releaseLock(key: string): Promise<void>
4
+ }
@@ -0,0 +1,36 @@
1
+ import { Injectable } from '@nestjs/common'
2
+ import { EnvConfig } from '../../core/utils/env.config'
3
+ import { IRedisService } from '../redis/iredis.service'
4
+ import { IRedLockService } from './ired-lock.service'
5
+
6
+ @Injectable()
7
+ export class RedLockService implements IRedLockService {
8
+ constructor(private readonly redisService: IRedisService) {}
9
+
10
+ async acquiredLock(key: string, ttlSecondsLock: number): Promise<boolean> {
11
+ if (EnvConfig.isEnvTest || !this.redisService.isConnected) {
12
+ return true
13
+ }
14
+
15
+ const lockKey = this.getLockKey(key)
16
+ const canLock = await this.redisService.getCache(lockKey)
17
+
18
+ if (canLock) {
19
+ return false
20
+ }
21
+
22
+ await this.redisService.setCache(lockKey, ttlSecondsLock, 'RedLockService')
23
+
24
+ return true
25
+ }
26
+
27
+ async releaseLock(key: string): Promise<void> {
28
+ if (!EnvConfig.isEnvTest && this.redisService.isConnected) {
29
+ await this.redisService.deleteCache(this.getLockKey(key))
30
+ }
31
+ }
32
+
33
+ private getLockKey(key: string) {
34
+ return `redLock:${key}`
35
+ }
36
+ }
@@ -0,0 +1,15 @@
1
+ import { Type } from '@nestjs/common'
2
+
3
+ interface KoalaAppTestDependenciesConfig {
4
+ dependencies: any[]
5
+ }
6
+
7
+ export class KoalaAppTestDependencies {
8
+ constructor(private readonly _config: KoalaAppTestDependenciesConfig) {}
9
+
10
+ get<T>(objectType: Type<T>): T {
11
+ return this._config.dependencies.find(
12
+ (dependency) => dependency instanceof objectType,
13
+ )
14
+ }
15
+ }
@@ -0,0 +1,103 @@
1
+ import { CanActivate, INestApplication, Type } from '@nestjs/common'
2
+ import { BaseExceptionFilter } from '@nestjs/core'
3
+ import { PrismaTransactionalClient } from '../core/database/prisma-transactional-client'
4
+ import { KoalaGlobalVars } from '../core/koala-global-vars'
5
+ import { instanciateClassWithDependenciesInjection } from '../core/utils/instanciate-class-with-dependencies-injection'
6
+ import { DomainErrorsFilter } from '../filters/domain-errors.filter'
7
+ import { GlobalExceptionsFilter } from '../filters/global-exception.filter'
8
+ import { PrismaValidationExceptionFilter } from '../filters/prisma-validation-exception.filter'
9
+ import { ZodErrorsFilter } from '../filters/zod-errors.filter'
10
+ import { ILoggingService } from '../services/logging/ilogging.service'
11
+
12
+ export class KoalaAppTest {
13
+ private _guards: CanActivate[] = []
14
+ private _globalExceptionFilter: BaseExceptionFilter
15
+ private _prismaValidationExceptionFilter: BaseExceptionFilter
16
+ private _domainExceptionFilter: BaseExceptionFilter
17
+ private _zodExceptionFilter: BaseExceptionFilter
18
+
19
+ constructor(private readonly app: INestApplication<any>) {
20
+ let loggingService = app.get(ILoggingService)
21
+
22
+ if (!loggingService.report) {
23
+ loggingService = instanciateClassWithDependenciesInjection(
24
+ this.app,
25
+ loggingService,
26
+ )
27
+ }
28
+
29
+ this._globalExceptionFilter = new GlobalExceptionsFilter(loggingService)
30
+ this._prismaValidationExceptionFilter = new PrismaValidationExceptionFilter(
31
+ loggingService,
32
+ )
33
+ this._domainExceptionFilter = new DomainErrorsFilter(loggingService)
34
+ this._zodExceptionFilter = new ZodErrorsFilter(loggingService)
35
+ }
36
+
37
+ addGlobalGuard(Guard: Type<CanActivate>) {
38
+ this._guards.push(
39
+ instanciateClassWithDependenciesInjection(this.app, Guard),
40
+ )
41
+ return this
42
+ }
43
+
44
+ addCustomGlobalExceptionFilter(filter: BaseExceptionFilter) {
45
+ this._globalExceptionFilter = filter
46
+ return this
47
+ }
48
+
49
+ addCustomPrismaValidationExceptionFilter(filter: BaseExceptionFilter) {
50
+ this._prismaValidationExceptionFilter = filter
51
+ return this
52
+ }
53
+
54
+ addCustomDomainExceptionFilter(filter: BaseExceptionFilter) {
55
+ this._domainExceptionFilter = filter
56
+ return this
57
+ }
58
+
59
+ addCustomZodExceptionFilter(filter: BaseExceptionFilter) {
60
+ this._zodExceptionFilter = filter
61
+ return this
62
+ }
63
+
64
+ enableCors() {
65
+ this.app.enableCors({
66
+ credentials: true,
67
+ origin: true,
68
+ optionsSuccessStatus: 200,
69
+ })
70
+
71
+ return this
72
+ }
73
+
74
+ setAppName(name: string) {
75
+ KoalaGlobalVars.appName = name
76
+ return this
77
+ }
78
+
79
+ setInternalUserName(name: string) {
80
+ KoalaGlobalVars.internalUserName = name
81
+ return this
82
+ }
83
+
84
+ setDbTransactionContext(transactionContext: Type<PrismaTransactionalClient>) {
85
+ KoalaGlobalVars.dbTransactionContext = transactionContext
86
+ return this
87
+ }
88
+
89
+ build() {
90
+ this.app.useGlobalFilters(
91
+ this._globalExceptionFilter,
92
+ this._prismaValidationExceptionFilter,
93
+ this._domainExceptionFilter,
94
+ this._zodExceptionFilter,
95
+ )
96
+
97
+ for (const guard of this._guards) {
98
+ this.app.useGlobalGuards(guard)
99
+ }
100
+
101
+ return this.app
102
+ }
103
+ }
@@ -0,0 +1,90 @@
1
+ import { QUERY_FILTER_PARAMS } from '@koalarx/nest/core/constants/query-params'
2
+ import { PaginationDto } from '@koalarx/nest/core/dtos/pagination.dto'
3
+ import { KlArray } from '@koalarx/utils/KlArray'
4
+ import { randomUUID } from 'node:crypto'
5
+ import { ListResponseBase } from '../../core/controllers/list-response.base'
6
+ import { EntityActionType, EntityBase } from '../../core/database/entity.base'
7
+ import { IComparableId } from '../../core/utils/interfaces/icomparable'
8
+
9
+ export abstract class InMemoryBaseRepository<TClass extends EntityBase<any>> {
10
+ protected items: TClass[] = []
11
+
12
+ constructor(private readonly typeId: 'number' | 'string' = 'number') {}
13
+
14
+ protected async findById(id: IComparableId): Promise<TClass | null> {
15
+ const entity = this.items.find((item) => item._id === id) ?? null
16
+
17
+ if (entity) {
18
+ entity._action = EntityActionType.update
19
+ }
20
+
21
+ return entity
22
+ }
23
+
24
+ protected async findMany<T extends PaginationDto>(
25
+ query: T,
26
+ predicate?: (value: TClass, index: number, array: TClass[]) => unknown,
27
+ ) {
28
+ const page = query.page ?? QUERY_FILTER_PARAMS.page
29
+ const limit = query.limit ?? QUERY_FILTER_PARAMS.limit
30
+
31
+ return new KlArray(predicate ? this.items.filter(predicate) : this.items)
32
+ .orderBy(query.orderBy ?? '', query.direction)
33
+ .slice(page * limit, (page + 1) * limit)
34
+ .map((item) => {
35
+ item._action = EntityActionType.update
36
+ return item
37
+ })
38
+ }
39
+
40
+ protected async findManyAndCount<T extends PaginationDto>(
41
+ query: T,
42
+ predicate?: (value: TClass, index: number, array: TClass[]) => unknown,
43
+ ): Promise<ListResponseBase<TClass>> {
44
+ const items = await this.findMany(query, predicate)
45
+
46
+ return {
47
+ items,
48
+ count: items.length,
49
+ }
50
+ }
51
+
52
+ protected async saveChanges(
53
+ item: TClass,
54
+ updateWhere?: (item: TClass) => boolean,
55
+ ) {
56
+ if (item._action === EntityActionType.create) {
57
+ const id = this.typeId === 'number' ? this.getNewId() : randomUUID()
58
+
59
+ item.automap({ ...item, id })
60
+
61
+ this.items.push(item)
62
+
63
+ return { id: item._id }
64
+ }
65
+
66
+ const predicate = updateWhere ?? ((itemDB) => itemDB.equals(item))
67
+ const itemIndex = this.items.findIndex(predicate)
68
+
69
+ if (itemIndex > -1) {
70
+ this.items[itemIndex] = item
71
+ }
72
+ }
73
+
74
+ protected async remove(
75
+ predicate: (value: TClass, index: number, obj: TClass[]) => unknown,
76
+ ) {
77
+ const itemIndex = this.items.findIndex(predicate)
78
+
79
+ if (itemIndex > -1) {
80
+ this.items.splice(itemIndex, 1)
81
+ }
82
+ }
83
+
84
+ private getNewId(): IComparableId {
85
+ return this.typeId === 'number'
86
+ ? (new KlArray(this.items).orderBy('_id', 'desc')[0]?._id as number) ??
87
+ 0 + 1
88
+ : randomUUID()
89
+ }
90
+ }
@@ -0,0 +1,7 @@
1
+ import { ILoggingService } from '../../services/logging/ilogging.service'
2
+
3
+ export class FakeLoggingService implements ILoggingService {
4
+ async report(data) {
5
+ console.log('FakeLoggingService.report', data)
6
+ }
7
+ }
@@ -0,0 +1,11 @@
1
+ import { IRedLockService } from '../../services/redlock/ired-lock.service'
2
+
3
+ export class FakeRedLockService implements IRedLockService {
4
+ async acquiredLock(key: string, ttlSecondsLock: number): Promise<boolean> {
5
+ return true
6
+ }
7
+
8
+ async releaseLock(key: string): Promise<void> {
9
+ //
10
+ }
11
+ }