@hed-hog/core 0.0.387 → 0.0.390

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 (535) hide show
  1. package/README.md +12 -11
  2. package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
  3. package/dist/access-log/access-log.interceptor.js +4 -2
  4. package/dist/access-log/access-log.interceptor.js.map +1 -1
  5. package/dist/ai/ai-attachment.fragments.d.ts +23 -0
  6. package/dist/ai/ai-attachment.fragments.d.ts.map +1 -0
  7. package/dist/ai/ai-attachment.fragments.js +34 -0
  8. package/dist/ai/ai-attachment.fragments.js.map +1 -0
  9. package/dist/ai/ai.controller.d.ts +7 -16
  10. package/dist/ai/ai.controller.d.ts.map +1 -1
  11. package/dist/ai/ai.prompts.d.ts +16 -0
  12. package/dist/ai/ai.prompts.d.ts.map +1 -0
  13. package/dist/ai/ai.prompts.js +37 -0
  14. package/dist/ai/ai.prompts.js.map +1 -0
  15. package/dist/ai/ai.service.d.ts +63 -12
  16. package/dist/ai/ai.service.d.ts.map +1 -1
  17. package/dist/ai/ai.service.js +215 -88
  18. package/dist/ai/ai.service.js.map +1 -1
  19. package/dist/ai/dto/chat.dto.d.ts +4 -1
  20. package/dist/ai/dto/chat.dto.d.ts.map +1 -1
  21. package/dist/ai/dto/chat.dto.js +23 -1
  22. package/dist/ai/dto/chat.dto.js.map +1 -1
  23. package/dist/ai/dto/create-agent.dto.d.ts +1 -1
  24. package/dist/ai/dto/create-agent.dto.d.ts.map +1 -1
  25. package/dist/ai/dto/create-agent.dto.js +1 -1
  26. package/dist/ai/dto/create-agent.dto.js.map +1 -1
  27. package/dist/ai/dto/update-agent.dto.d.ts +1 -1
  28. package/dist/ai/dto/update-agent.dto.d.ts.map +1 -1
  29. package/dist/ai/dto/update-agent.dto.js +1 -1
  30. package/dist/ai/dto/update-agent.dto.js.map +1 -1
  31. package/dist/ai-instruction/ai-instruction.controller.d.ts +61 -7
  32. package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -1
  33. package/dist/ai-instruction/ai-instruction.controller.js +63 -20
  34. package/dist/ai-instruction/ai-instruction.controller.js.map +1 -1
  35. package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -1
  36. package/dist/ai-instruction/ai-instruction.module.js +13 -2
  37. package/dist/ai-instruction/ai-instruction.module.js.map +1 -1
  38. package/dist/ai-instruction/ai-instruction.service.d.ts +131 -6
  39. package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
  40. package/dist/ai-instruction/ai-instruction.service.js +533 -60
  41. package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
  42. package/dist/ai-instruction/ai-prompt-builder.service.d.ts +8 -0
  43. package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -1
  44. package/dist/ai-instruction/ai-prompt-builder.service.js +10 -1
  45. package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -1
  46. package/dist/ai-instruction/ai-prompt-registry.d.ts +45 -0
  47. package/dist/ai-instruction/ai-prompt-registry.d.ts.map +1 -0
  48. package/dist/ai-instruction/ai-prompt-registry.js +49 -0
  49. package/dist/ai-instruction/ai-prompt-registry.js.map +1 -0
  50. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +89 -0
  51. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -0
  52. package/dist/ai-instruction/ai-prompt-resolver.service.js +222 -0
  53. package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -0
  54. package/dist/ai-instruction/ai-prompt-template.util.d.ts +70 -0
  55. package/dist/ai-instruction/ai-prompt-template.util.d.ts.map +1 -0
  56. package/dist/ai-instruction/ai-prompt-template.util.js +154 -0
  57. package/dist/ai-instruction/ai-prompt-template.util.js.map +1 -0
  58. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +5 -0
  59. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -1
  60. package/dist/ai-instruction/dto/create-ai-instruction.dto.js +27 -1
  61. package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -1
  62. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts +14 -0
  63. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts.map +1 -0
  64. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js +42 -0
  65. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js.map +1 -0
  66. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +11 -0
  67. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -1
  68. package/dist/ai-instruction/dto/update-ai-instruction.dto.js +34 -0
  69. package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -1
  70. package/dist/ai-instruction/types/ai-instruction.types.d.ts +13 -1
  71. package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -1
  72. package/dist/ai-instruction/types/ai-instruction.types.js +10 -0
  73. package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -1
  74. package/dist/auth/auth.controller.d.ts +24 -9
  75. package/dist/auth/auth.controller.d.ts.map +1 -1
  76. package/dist/auth/auth.controller.js +49 -21
  77. package/dist/auth/auth.controller.js.map +1 -1
  78. package/dist/auth/auth.service.d.ts +33 -8
  79. package/dist/auth/auth.service.d.ts.map +1 -1
  80. package/dist/auth/auth.service.js +78 -29
  81. package/dist/auth/auth.service.js.map +1 -1
  82. package/dist/captcha/captcha.module.d.ts +3 -0
  83. package/dist/captcha/captcha.module.d.ts.map +1 -0
  84. package/dist/captcha/captcha.module.js +23 -0
  85. package/dist/captcha/captcha.module.js.map +1 -0
  86. package/dist/captcha/captcha.service.d.ts +38 -0
  87. package/dist/captcha/captcha.service.d.ts.map +1 -0
  88. package/dist/captcha/captcha.service.js +144 -0
  89. package/dist/captcha/captcha.service.js.map +1 -0
  90. package/dist/challenge/challenge.service.d.ts +16 -7
  91. package/dist/challenge/challenge.service.d.ts.map +1 -1
  92. package/dist/challenge/challenge.service.js +64 -16
  93. package/dist/challenge/challenge.service.js.map +1 -1
  94. package/dist/core.module.d.ts +3 -1
  95. package/dist/core.module.d.ts.map +1 -1
  96. package/dist/core.module.js +29 -2
  97. package/dist/core.module.js.map +1 -1
  98. package/dist/dashboard/dashboard/dashboard.controller.d.ts +15 -15
  99. package/dist/dashboard/dashboard/dashboard.service.d.ts +15 -15
  100. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +6 -6
  101. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +6 -6
  102. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +20 -20
  103. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +20 -20
  104. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
  105. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +1 -1
  106. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +13 -13
  107. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +13 -13
  108. package/dist/file/file.service.d.ts +6 -0
  109. package/dist/file/file.service.d.ts.map +1 -1
  110. package/dist/file/file.service.js +44 -4
  111. package/dist/file/file.service.js.map +1 -1
  112. package/dist/incident/incident-notifier.service.d.ts +36 -0
  113. package/dist/incident/incident-notifier.service.d.ts.map +1 -0
  114. package/dist/incident/incident-notifier.service.js +208 -0
  115. package/dist/incident/incident-notifier.service.js.map +1 -0
  116. package/dist/incident/incident.controller.d.ts +23 -0
  117. package/dist/incident/incident.controller.d.ts.map +1 -0
  118. package/dist/incident/incident.controller.js +75 -0
  119. package/dist/incident/incident.controller.js.map +1 -0
  120. package/dist/incident/incident.module.d.ts +7 -0
  121. package/dist/incident/incident.module.d.ts.map +1 -0
  122. package/dist/incident/incident.module.js +32 -0
  123. package/dist/incident/incident.module.js.map +1 -0
  124. package/dist/incident/incident.service.d.ts +72 -0
  125. package/dist/incident/incident.service.d.ts.map +1 -0
  126. package/dist/incident/incident.service.js +184 -0
  127. package/dist/incident/incident.service.js.map +1 -0
  128. package/dist/index.d.ts +26 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +30 -0
  131. package/dist/index.js.map +1 -1
  132. package/dist/integration-profile/dto/test.dto.d.ts +13 -0
  133. package/dist/integration-profile/dto/test.dto.d.ts.map +1 -0
  134. package/dist/integration-profile/dto/test.dto.js +26 -0
  135. package/dist/integration-profile/dto/test.dto.js.map +1 -0
  136. package/dist/integration-profile/integration-profile.controller.d.ts +12 -1
  137. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
  138. package/dist/integration-profile/integration-profile.controller.js +9 -1
  139. package/dist/integration-profile/integration-profile.controller.js.map +1 -1
  140. package/dist/integration-profile/integration-profile.module.d.ts +6 -1
  141. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
  142. package/dist/integration-profile/integration-profile.module.js +26 -3
  143. package/dist/integration-profile/integration-profile.module.js.map +1 -1
  144. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  145. package/dist/integration-profile/integration-profile.secrets.js +9 -1
  146. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  147. package/dist/integration-profile/integration-profile.service.d.ts +26 -7
  148. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  149. package/dist/integration-profile/integration-profile.service.js +94 -91
  150. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  151. package/dist/integration-profile/integration-profile.utils.d.ts +13 -1
  152. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  153. package/dist/integration-profile/integration-profile.utils.js +20 -5
  154. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  155. package/dist/integration-profile/testers/ai.testers.d.ts +3 -0
  156. package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -0
  157. package/dist/integration-profile/testers/ai.testers.js +125 -0
  158. package/dist/integration-profile/testers/ai.testers.js.map +1 -0
  159. package/dist/integration-profile/testers/captcha.testers.d.ts +3 -0
  160. package/dist/integration-profile/testers/captcha.testers.d.ts.map +1 -0
  161. package/dist/integration-profile/testers/captcha.testers.js +121 -0
  162. package/dist/integration-profile/testers/captcha.testers.js.map +1 -0
  163. package/dist/integration-profile/testers/email.testers.d.ts +3 -0
  164. package/dist/integration-profile/testers/email.testers.d.ts.map +1 -0
  165. package/dist/integration-profile/testers/email.testers.js +128 -0
  166. package/dist/integration-profile/testers/email.testers.js.map +1 -0
  167. package/dist/integration-profile/testers/http-probe.d.ts +57 -0
  168. package/dist/integration-profile/testers/http-probe.d.ts.map +1 -0
  169. package/dist/integration-profile/testers/http-probe.js +140 -0
  170. package/dist/integration-profile/testers/http-probe.js.map +1 -0
  171. package/dist/integration-profile/testers/index.d.ts +12 -0
  172. package/dist/integration-profile/testers/index.d.ts.map +1 -0
  173. package/dist/integration-profile/testers/index.js +45 -0
  174. package/dist/integration-profile/testers/index.js.map +1 -0
  175. package/dist/integration-profile/testers/infrastructure.testers.d.ts +3 -0
  176. package/dist/integration-profile/testers/infrastructure.testers.d.ts.map +1 -0
  177. package/dist/integration-profile/testers/infrastructure.testers.js +105 -0
  178. package/dist/integration-profile/testers/infrastructure.testers.js.map +1 -0
  179. package/dist/integration-profile/testers/integration-tester.registry.d.ts +17 -0
  180. package/dist/integration-profile/testers/integration-tester.registry.d.ts.map +1 -0
  181. package/dist/integration-profile/testers/integration-tester.registry.js +52 -0
  182. package/dist/integration-profile/testers/integration-tester.registry.js.map +1 -0
  183. package/dist/integration-profile/testers/integration-tester.types.d.ts +55 -0
  184. package/dist/integration-profile/testers/integration-tester.types.d.ts.map +1 -0
  185. package/dist/integration-profile/testers/integration-tester.types.js +16 -0
  186. package/dist/integration-profile/testers/integration-tester.types.js.map +1 -0
  187. package/dist/integration-profile/testers/messaging.testers.d.ts +3 -0
  188. package/dist/integration-profile/testers/messaging.testers.d.ts.map +1 -0
  189. package/dist/integration-profile/testers/messaging.testers.js +70 -0
  190. package/dist/integration-profile/testers/messaging.testers.js.map +1 -0
  191. package/dist/integration-profile/testers/oauth.testers.d.ts +3 -0
  192. package/dist/integration-profile/testers/oauth.testers.d.ts.map +1 -0
  193. package/dist/integration-profile/testers/oauth.testers.js +285 -0
  194. package/dist/integration-profile/testers/oauth.testers.js.map +1 -0
  195. package/dist/integration-profile/testers/payment.testers.d.ts +3 -0
  196. package/dist/integration-profile/testers/payment.testers.d.ts.map +1 -0
  197. package/dist/integration-profile/testers/payment.testers.js +169 -0
  198. package/dist/integration-profile/testers/payment.testers.js.map +1 -0
  199. package/dist/integration-profile/testers/storage.testers.d.ts +3 -0
  200. package/dist/integration-profile/testers/storage.testers.d.ts.map +1 -0
  201. package/dist/integration-profile/testers/storage.testers.js +208 -0
  202. package/dist/integration-profile/testers/storage.testers.js.map +1 -0
  203. package/dist/language/en.json +4 -2
  204. package/dist/language/pt.json +4 -2
  205. package/dist/leaked-password/leaked-password.controller.d.ts +24 -0
  206. package/dist/leaked-password/leaked-password.controller.d.ts.map +1 -0
  207. package/dist/leaked-password/leaked-password.controller.js +78 -0
  208. package/dist/leaked-password/leaked-password.controller.js.map +1 -0
  209. package/dist/leaked-password/leaked-password.module.d.ts +8 -0
  210. package/dist/leaked-password/leaked-password.module.d.ts.map +1 -0
  211. package/dist/leaked-password/leaked-password.module.js +31 -0
  212. package/dist/leaked-password/leaked-password.module.js.map +1 -0
  213. package/dist/leaked-password/leaked-password.service.d.ts +64 -0
  214. package/dist/leaked-password/leaked-password.service.d.ts.map +1 -0
  215. package/dist/leaked-password/leaked-password.service.js +218 -0
  216. package/dist/leaked-password/leaked-password.service.js.map +1 -0
  217. package/dist/locale/locale.controller.d.ts +1 -1
  218. package/dist/locale/locale.service.d.ts +1 -1
  219. package/dist/mail/dto/preview.dto.d.ts +18 -0
  220. package/dist/mail/dto/preview.dto.d.ts.map +1 -0
  221. package/dist/mail/dto/preview.dto.js +66 -0
  222. package/dist/mail/dto/preview.dto.js.map +1 -0
  223. package/dist/mail/dto/send.dto.d.ts +7 -0
  224. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  225. package/dist/mail/dto/send.dto.js +10 -0
  226. package/dist/mail/dto/send.dto.js.map +1 -1
  227. package/dist/mail/mail.controller.d.ts +4 -0
  228. package/dist/mail/mail.controller.d.ts.map +1 -1
  229. package/dist/mail/mail.controller.js +16 -2
  230. package/dist/mail/mail.controller.js.map +1 -1
  231. package/dist/mail/mail.service.d.ts +23 -2
  232. package/dist/mail/mail.service.d.ts.map +1 -1
  233. package/dist/mail/mail.service.js +102 -13
  234. package/dist/mail/mail.service.js.map +1 -1
  235. package/dist/mail-layout/dto/update.dto.d.ts +17 -0
  236. package/dist/mail-layout/dto/update.dto.d.ts.map +1 -0
  237. package/dist/mail-layout/dto/update.dto.js +27 -0
  238. package/dist/mail-layout/dto/update.dto.js.map +1 -0
  239. package/dist/mail-layout/mail-layout.controller.d.ts +15 -0
  240. package/dist/mail-layout/mail-layout.controller.d.ts.map +1 -0
  241. package/dist/mail-layout/mail-layout.controller.js +71 -0
  242. package/dist/mail-layout/mail-layout.controller.js.map +1 -0
  243. package/dist/mail-layout/mail-layout.module.d.ts +3 -0
  244. package/dist/mail-layout/mail-layout.module.d.ts.map +1 -0
  245. package/dist/mail-layout/mail-layout.module.js +35 -0
  246. package/dist/mail-layout/mail-layout.module.js.map +1 -0
  247. package/dist/mail-layout/mail-layout.service.d.ts +27 -0
  248. package/dist/mail-layout/mail-layout.service.d.ts.map +1 -0
  249. package/dist/mail-layout/mail-layout.service.js +80 -0
  250. package/dist/mail-layout/mail-layout.service.js.map +1 -0
  251. package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
  252. package/dist/mcp-chat/mcp-chat.service.d.ts +24 -2
  253. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  254. package/dist/mcp-chat/mcp-chat.service.js +80 -24
  255. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  256. package/dist/menu/menu.controller.d.ts +3 -3
  257. package/dist/menu/menu.service.d.ts +3 -3
  258. package/dist/notification/notification.controller.d.ts +12 -12
  259. package/dist/notification/notification.service.d.ts +12 -12
  260. package/dist/oauth/oauth-token-broker.service.d.ts +72 -0
  261. package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -0
  262. package/dist/oauth/oauth-token-broker.service.js +258 -0
  263. package/dist/oauth/oauth-token-broker.service.js.map +1 -0
  264. package/dist/oauth/oauth.module.d.ts.map +1 -1
  265. package/dist/oauth/oauth.module.js +3 -1
  266. package/dist/oauth/oauth.module.js.map +1 -1
  267. package/dist/oauth/oauth.service.d.ts +2 -0
  268. package/dist/oauth/oauth.service.d.ts.map +1 -1
  269. package/dist/oauth/oauth.service.js +6 -3
  270. package/dist/oauth/oauth.service.js.map +1 -1
  271. package/dist/pdf/pdf.service.d.ts +8 -0
  272. package/dist/pdf/pdf.service.d.ts.map +1 -1
  273. package/dist/pdf/pdf.service.js +52 -0
  274. package/dist/pdf/pdf.service.js.map +1 -1
  275. package/dist/presence/presence.controller.d.ts +16 -0
  276. package/dist/presence/presence.controller.d.ts.map +1 -0
  277. package/dist/presence/presence.controller.js +60 -0
  278. package/dist/presence/presence.controller.js.map +1 -0
  279. package/dist/presence/presence.listener.d.ts +29 -0
  280. package/dist/presence/presence.listener.d.ts.map +1 -0
  281. package/dist/presence/presence.listener.js +82 -0
  282. package/dist/presence/presence.listener.js.map +1 -0
  283. package/dist/presence/presence.module.d.ts +3 -0
  284. package/dist/presence/presence.module.d.ts.map +1 -0
  285. package/dist/presence/presence.module.js +32 -0
  286. package/dist/presence/presence.module.js.map +1 -0
  287. package/dist/presence/presence.service.d.ts +42 -0
  288. package/dist/presence/presence.service.d.ts.map +1 -0
  289. package/dist/presence/presence.service.js +147 -0
  290. package/dist/presence/presence.service.js.map +1 -0
  291. package/dist/profile/dto/delete-account.dto.d.ts +8 -0
  292. package/dist/profile/dto/delete-account.dto.d.ts.map +1 -0
  293. package/dist/profile/dto/delete-account.dto.js +22 -0
  294. package/dist/profile/dto/delete-account.dto.js.map +1 -0
  295. package/dist/profile/events/profile-account-deleted.event.d.ts +12 -0
  296. package/dist/profile/events/profile-account-deleted.event.d.ts.map +1 -0
  297. package/dist/profile/events/profile-account-deleted.event.js +17 -0
  298. package/dist/profile/events/profile-account-deleted.event.js.map +1 -0
  299. package/dist/profile/profile.controller.d.ts +21 -15
  300. package/dist/profile/profile.controller.d.ts.map +1 -1
  301. package/dist/profile/profile.controller.js +75 -46
  302. package/dist/profile/profile.controller.js.map +1 -1
  303. package/dist/profile/profile.service.d.ts +30 -18
  304. package/dist/profile/profile.service.d.ts.map +1 -1
  305. package/dist/profile/profile.service.js +113 -37
  306. package/dist/profile/profile.service.js.map +1 -1
  307. package/dist/realtime/realtime.gateway.d.ts +48 -0
  308. package/dist/realtime/realtime.gateway.d.ts.map +1 -0
  309. package/dist/realtime/realtime.gateway.js +156 -0
  310. package/dist/realtime/realtime.gateway.js.map +1 -0
  311. package/dist/realtime/realtime.module.d.ts +8 -0
  312. package/dist/realtime/realtime.module.d.ts.map +1 -0
  313. package/dist/realtime/realtime.module.js +29 -0
  314. package/dist/realtime/realtime.module.js.map +1 -0
  315. package/dist/realtime/realtime.service.d.ts +51 -0
  316. package/dist/realtime/realtime.service.d.ts.map +1 -0
  317. package/dist/realtime/realtime.service.js +177 -0
  318. package/dist/realtime/realtime.service.js.map +1 -0
  319. package/dist/redis/redis-pubsub.d.ts +27 -0
  320. package/dist/redis/redis-pubsub.d.ts.map +1 -0
  321. package/dist/redis/redis-pubsub.js +140 -0
  322. package/dist/redis/redis-pubsub.js.map +1 -0
  323. package/dist/role/role.controller.d.ts +3 -3
  324. package/dist/role/role.service.d.ts +3 -3
  325. package/dist/setting/dto/create.dto.d.ts.map +1 -1
  326. package/dist/setting/dto/create.dto.js +9 -2
  327. package/dist/setting/dto/create.dto.js.map +1 -1
  328. package/dist/setting/setting.controller.d.ts +5 -5
  329. package/dist/setting/setting.service.d.ts +8 -5
  330. package/dist/setting/setting.service.d.ts.map +1 -1
  331. package/dist/setting/setting.service.js +25 -1
  332. package/dist/setting/setting.service.js.map +1 -1
  333. package/dist/user/dto/create-with-email-and-password.dto.d.ts +2 -0
  334. package/dist/user/dto/create-with-email-and-password.dto.d.ts.map +1 -1
  335. package/dist/user/dto/create-with-email-and-password.dto.js +5 -0
  336. package/dist/user/dto/create-with-email-and-password.dto.js.map +1 -1
  337. package/dist/user/dto/query-user-mail-list.dto.d.ts +5 -0
  338. package/dist/user/dto/query-user-mail-list.dto.d.ts.map +1 -0
  339. package/dist/user/dto/query-user-mail-list.dto.js +25 -0
  340. package/dist/user/dto/query-user-mail-list.dto.js.map +1 -0
  341. package/dist/user/user-credential.util.d.ts +19 -0
  342. package/dist/user/user-credential.util.d.ts.map +1 -0
  343. package/dist/user/user-credential.util.js +32 -0
  344. package/dist/user/user-credential.util.js.map +1 -0
  345. package/dist/user/user.controller.d.ts +17 -5
  346. package/dist/user/user.controller.d.ts.map +1 -1
  347. package/dist/user/user.controller.js +18 -3
  348. package/dist/user/user.controller.js.map +1 -1
  349. package/dist/user/user.service.d.ts +28 -6
  350. package/dist/user/user.service.d.ts.map +1 -1
  351. package/dist/user/user.service.js +204 -13
  352. package/dist/user/user.service.js.map +1 -1
  353. package/dist/validators/is-strong-password-with-settings.validator.d.ts.map +1 -1
  354. package/dist/validators/is-strong-password-with-settings.validator.js +11 -0
  355. package/dist/validators/is-strong-password-with-settings.validator.js.map +1 -1
  356. package/dist/validators/service-locator.d.ts +9 -0
  357. package/dist/validators/service-locator.d.ts.map +1 -1
  358. package/dist/validators/service-locator.js +12 -0
  359. package/dist/validators/service-locator.js.map +1 -1
  360. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
  361. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
  362. package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
  363. package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
  364. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
  365. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
  366. package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
  367. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
  368. package/hedhog/data/integration_provider.yaml +16 -0
  369. package/hedhog/data/mail.yaml +88 -61
  370. package/hedhog/data/mail_layout.yaml +188 -0
  371. package/hedhog/data/menu.yaml +67 -3
  372. package/hedhog/data/route.yaml +135 -0
  373. package/hedhog/data/setting_group.yaml +139 -1
  374. package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
  375. package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
  376. package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
  377. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
  378. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
  379. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
  380. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
  381. package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
  382. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
  383. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
  384. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
  385. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
  386. package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
  387. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
  388. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
  389. package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
  390. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +153 -84
  391. package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
  392. package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
  393. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
  394. package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
  395. package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
  396. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
  397. package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
  398. package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
  399. package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
  400. package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
  401. package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
  402. package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
  403. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
  404. package/hedhog/frontend/messages/en.json +499 -3
  405. package/hedhog/frontend/messages/pt.json +499 -3
  406. package/hedhog/table/ai_agent.yaml +1 -0
  407. package/hedhog/table/ai_instruction.yaml +15 -0
  408. package/hedhog/table/leaked_password.yaml +18 -0
  409. package/hedhog/table/mail_layout.yaml +35 -0
  410. package/hedhog/table/mail_var.yaml +4 -0
  411. package/hedhog/table/setting.yaml +1 -0
  412. package/hedhog/table/system_incident.yaml +59 -0
  413. package/hedhog/table/user_presence.yaml +36 -0
  414. package/package.json +8 -4
  415. package/src/access-log/access-log.interceptor.ts +4 -2
  416. package/src/ai/ai-attachment.fragments.spec.ts +319 -0
  417. package/src/ai/ai-attachment.fragments.ts +35 -0
  418. package/src/ai/ai.prompts.ts +38 -0
  419. package/src/ai/ai.service.spec.ts +280 -0
  420. package/src/ai/ai.service.ts +338 -82
  421. package/src/ai/dto/chat.dto.ts +33 -3
  422. package/src/ai/dto/create-agent.dto.ts +2 -2
  423. package/src/ai/dto/update-agent.dto.ts +2 -2
  424. package/src/ai-instruction/ai-instruction.controller.ts +40 -9
  425. package/src/ai-instruction/ai-instruction.module.ts +13 -2
  426. package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
  427. package/src/ai-instruction/ai-instruction.service.ts +661 -62
  428. package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
  429. package/src/ai-instruction/ai-prompt-registry.ts +87 -0
  430. package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
  431. package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
  432. package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
  433. package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
  434. package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
  435. package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
  436. package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
  437. package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
  438. package/src/auth/auth.controller.ts +31 -5
  439. package/src/auth/auth.service.spec.ts +3 -1
  440. package/src/auth/auth.service.ts +101 -36
  441. package/src/captcha/captcha.module.ts +10 -0
  442. package/src/captcha/captcha.service.spec.ts +210 -0
  443. package/src/captcha/captcha.service.ts +191 -0
  444. package/src/challenge/challenge.service.spec.ts +39 -4
  445. package/src/challenge/challenge.service.ts +72 -17
  446. package/src/core.module.ts +27 -1
  447. package/src/file/file.service.spec.ts +105 -0
  448. package/src/file/file.service.ts +60 -3
  449. package/src/incident/incident-notifier.service.spec.ts +205 -0
  450. package/src/incident/incident-notifier.service.ts +241 -0
  451. package/src/incident/incident.controller.ts +38 -0
  452. package/src/incident/incident.module.ts +19 -0
  453. package/src/incident/incident.service.spec.ts +150 -0
  454. package/src/incident/incident.service.ts +209 -0
  455. package/src/index.ts +37 -0
  456. package/src/integration-profile/dto/test.dto.ts +19 -0
  457. package/src/integration-profile/integration-profile.controller.ts +10 -1
  458. package/src/integration-profile/integration-profile.module.spec.ts +51 -0
  459. package/src/integration-profile/integration-profile.module.ts +23 -4
  460. package/src/integration-profile/integration-profile.secrets.ts +9 -1
  461. package/src/integration-profile/integration-profile.service.spec.ts +279 -0
  462. package/src/integration-profile/integration-profile.service.ts +120 -124
  463. package/src/integration-profile/integration-profile.utils.spec.ts +22 -0
  464. package/src/integration-profile/integration-profile.utils.ts +40 -3
  465. package/src/integration-profile/testers/ai.testers.ts +165 -0
  466. package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
  467. package/src/integration-profile/testers/captcha.testers.ts +139 -0
  468. package/src/integration-profile/testers/email.testers.ts +161 -0
  469. package/src/integration-profile/testers/http-probe.spec.ts +153 -0
  470. package/src/integration-profile/testers/http-probe.ts +171 -0
  471. package/src/integration-profile/testers/index.ts +30 -0
  472. package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
  473. package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
  474. package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
  475. package/src/integration-profile/testers/integration-tester.types.ts +61 -0
  476. package/src/integration-profile/testers/messaging.testers.ts +102 -0
  477. package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
  478. package/src/integration-profile/testers/oauth.testers.ts +305 -0
  479. package/src/integration-profile/testers/payment.testers.ts +185 -0
  480. package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
  481. package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
  482. package/src/integration-profile/testers/storage.testers.ts +226 -0
  483. package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
  484. package/src/language/en.json +4 -2
  485. package/src/language/pt.json +4 -2
  486. package/src/leaked-password/README.md +83 -0
  487. package/src/leaked-password/leaked-password.controller.ts +52 -0
  488. package/src/leaked-password/leaked-password.module.ts +18 -0
  489. package/src/leaked-password/leaked-password.service.ts +242 -0
  490. package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
  491. package/src/leaked-password/seed/common-passwords.txt +335 -0
  492. package/src/mail/dto/preview.dto.ts +50 -0
  493. package/src/mail/dto/send.dto.ts +14 -1
  494. package/src/mail/mail-template.spec.ts +197 -0
  495. package/src/mail/mail.controller.ts +9 -2
  496. package/src/mail/mail.service.spec.ts +116 -1
  497. package/src/mail/mail.service.ts +118 -12
  498. package/src/mail-layout/dto/update.dto.ts +19 -0
  499. package/src/mail-layout/mail-layout.controller.ts +47 -0
  500. package/src/mail-layout/mail-layout.module.ts +22 -0
  501. package/src/mail-layout/mail-layout.service.ts +94 -0
  502. package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
  503. package/src/mcp-chat/mcp-chat.service.ts +122 -26
  504. package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
  505. package/src/oauth/oauth-token-broker.service.ts +363 -0
  506. package/src/oauth/oauth.module.ts +3 -1
  507. package/src/oauth/oauth.service.ts +8 -2
  508. package/src/pdf/pdf.service.ts +75 -0
  509. package/src/presence/presence.controller.ts +29 -0
  510. package/src/presence/presence.listener.ts +53 -0
  511. package/src/presence/presence.module.ts +19 -0
  512. package/src/presence/presence.service.spec.ts +97 -0
  513. package/src/presence/presence.service.ts +160 -0
  514. package/src/profile/dto/delete-account.dto.ts +11 -0
  515. package/src/profile/events/profile-account-deleted.event.ts +13 -0
  516. package/src/profile/profile.controller.ts +46 -34
  517. package/src/profile/profile.service.ts +138 -38
  518. package/src/realtime/realtime.gateway.ts +138 -0
  519. package/src/realtime/realtime.module.ts +16 -0
  520. package/src/realtime/realtime.service.spec.ts +50 -0
  521. package/src/realtime/realtime.service.ts +187 -0
  522. package/src/redis/redis-pubsub.ts +179 -0
  523. package/src/setting/dto/create.dto.ts +13 -2
  524. package/src/setting/setting.service.spec.ts +56 -0
  525. package/src/setting/setting.service.ts +29 -1
  526. package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
  527. package/src/user/dto/query-user-mail-list.dto.ts +10 -0
  528. package/src/user/user-credential.util.ts +35 -0
  529. package/src/user/user.controller.ts +17 -2
  530. package/src/user/user.service.spec.ts +153 -0
  531. package/src/user/user.service.ts +255 -12
  532. package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
  533. package/src/validators/service-locator.ts +15 -0
  534. package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
  535. package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
@@ -19,6 +19,10 @@ import { InstallModule } from './install/install.module';
19
19
  import { IntegrationModule } from './integration/integration.module';
20
20
  import { LocaleModule as CoreLocaleModule } from './locale/locale.module';
21
21
  import { MailSentModule } from './mail-sent/mail-sent.module';
22
+ import { IncidentModule } from './incident/incident.module';
23
+ import { LeakedPasswordModule } from './leaked-password/leaked-password.module';
24
+ import { LeakedPasswordService } from './leaked-password/leaked-password.service';
25
+ import { MailLayoutModule } from './mail-layout/mail-layout.module';
22
26
  import { MailModule } from './mail/mail.module';
23
27
  import { McpChatModule } from './mcp-chat/mcp-chat.module';
24
28
  import { McpModule } from './mcp/mcp.module';
@@ -26,11 +30,14 @@ import { MenuModule } from './menu/menu.module';
26
30
  import { LocaleInjectionMiddleware } from './middlewares/locale-injection.middleware';
27
31
  import { NotificationModule } from './notification/notification.module';
28
32
  import { OAuthModule } from './oauth/oauth.module';
33
+ import { PresenceModule } from './presence/presence.module';
34
+ import { RealtimeModule } from './realtime/realtime.module';
29
35
  import { PdfModule } from './pdf/pdf.module';
30
36
  import { ProfileModule } from './profile/profile.module';
31
37
  import { RoleModule } from './role/role.module';
32
38
  import { RouteModule } from './route/route.module';
33
39
  import { ScreenModule } from './screen/screen.module';
40
+ import { CaptchaModule } from './captcha/captcha.module';
34
41
  import { SecurityModule } from './security/security.module';
35
42
  import { SessionModule } from './session/session.module';
36
43
  import { SettingModule } from './setting/setting.module';
@@ -45,6 +52,7 @@ import { AiInstructionModule } from './ai-instruction/ai-instruction.module';
45
52
  import { AuthorizeModule } from './authorize/authorize.module';
46
53
  import { IntegrationProfileModule } from './integration-profile/integration-profile.module';
47
54
  import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
55
+ import { WhatsappSenderModule } from './whatsapp-sender/whatsapp-sender.module';
48
56
 
49
57
  @Global()
50
58
  @Module({
@@ -68,12 +76,17 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
68
76
  forwardRef(() => UserModule),
69
77
  forwardRef(() => SystemModule),
70
78
  forwardRef(() => SettingModule),
79
+ forwardRef(() => IncidentModule),
80
+ forwardRef(() => LeakedPasswordModule),
71
81
  forwardRef(() => MailModule),
82
+ forwardRef(() => MailLayoutModule),
72
83
  forwardRef(() => IntegrationProfileModule),
84
+ forwardRef(() => WhatsappSenderModule),
73
85
  forwardRef(() => MailSentModule),
74
86
  forwardRef(() => FileModule),
75
87
  forwardRef(() => TaskModule),
76
88
  forwardRef(() => SecurityModule),
89
+ forwardRef(() => CaptchaModule),
77
90
  forwardRef(() => ProfileModule),
78
91
  forwardRef(() => SessionModule),
79
92
  forwardRef(() => OAuthModule),
@@ -85,12 +98,18 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
85
98
  forwardRef(() => PdfModule),
86
99
  forwardRef(() => NotificationModule),
87
100
  forwardRef(() => AccessLogModule),
101
+ forwardRef(() => RealtimeModule),
102
+ forwardRef(() => PresenceModule),
88
103
  ],
89
104
  exports: [
90
105
  UserModule,
91
106
  AuthModule,
107
+ IncidentModule,
108
+ LeakedPasswordModule,
92
109
  MailModule,
110
+ MailLayoutModule,
93
111
  IntegrationProfileModule,
112
+ WhatsappSenderModule,
94
113
  RouteModule,
95
114
  RoleModule,
96
115
  MenuModule,
@@ -104,12 +123,16 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
104
123
  AiInstructionModule,
105
124
  IntegrationModule,
106
125
  WebhookIntegrationModule,
126
+ OAuthModule,
107
127
  IsStrongPasswordWithSettingsConstraint,
108
128
  IsEmailWithSettingsConstraint,
109
129
  IsPinCodeWithSettingConstraint,
110
130
  PdfModule,
111
131
  NotificationModule,
112
132
  AccessLogModule,
133
+ RealtimeModule,
134
+ PresenceModule,
135
+ CaptchaModule,
113
136
  ],
114
137
  providers: [
115
138
  Reflector,
@@ -135,12 +158,15 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
135
158
  export class CoreModule implements NestModule, OnModuleInit {
136
159
  constructor(
137
160
  @Inject(forwardRef(() => SettingService))
138
- private readonly settingService: SettingService
161
+ private readonly settingService: SettingService,
162
+ @Inject(forwardRef(() => LeakedPasswordService))
163
+ private readonly leakedPasswordService: LeakedPasswordService
139
164
  ) {}
140
165
 
141
166
  onModuleInit() {
142
167
  // Initialize the service locator for validators
143
168
  ValidatorServiceLocator.setSettingService(this.settingService);
169
+ ValidatorServiceLocator.setLeakedPasswordService(this.leakedPasswordService);
144
170
  }
145
171
 
146
172
  configure(consumer: MiddlewareConsumer) {
@@ -0,0 +1,105 @@
1
+ import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
2
+ import { FileService } from './file.service';
3
+ import { ProviderFactory } from './provider/provider.factory';
4
+
5
+ /**
6
+ * Resolver o provider custava 3 queries + a reconstrução do client de storage por arquivo.
7
+ * Em upload em massa (segmentos HLS em lotes paralelos, frames, pacotes SCORM) isso virava
8
+ * milhares de round-trips simultâneos e estourava o pool de conexões no meio da conversão.
9
+ */
10
+ describe('FileService.getProvider', () => {
11
+ let deps: any;
12
+ let service: FileService;
13
+ let createSpy: jest.SpiedFunction<typeof ProviderFactory.create>;
14
+
15
+ beforeEach(() => {
16
+ deps = {
17
+ prisma: {
18
+ integration_profile: {
19
+ findUnique: jest.fn().mockResolvedValue({
20
+ slug: 'spaces',
21
+ config: {},
22
+ integration_type: { slug: 'storage' },
23
+ integration_provider: { slug: 's3-compatible' },
24
+ } as never),
25
+ },
26
+ file_provider: {
27
+ findFirst: jest.fn().mockResolvedValue({ id: 7 } as never),
28
+ },
29
+ },
30
+ pagination: {},
31
+ setting: {
32
+ getSettingValues: jest
33
+ .fn()
34
+ .mockResolvedValue({ 'file-storage-profile-id': 'spaces' } as never),
35
+ },
36
+ jwt: {},
37
+ imageOptimization: {},
38
+ };
39
+
40
+ createSpy = jest
41
+ .spyOn(ProviderFactory, 'create')
42
+ .mockResolvedValue({ name: 'spaces-provider' } as never);
43
+
44
+ service = new FileService(
45
+ deps.prisma,
46
+ deps.pagination,
47
+ deps.setting,
48
+ deps.jwt,
49
+ deps.imageOptimization,
50
+ );
51
+ });
52
+
53
+ afterEach(() => jest.restoreAllMocks());
54
+
55
+ it('resolve uma vez e reaproveita dentro da janela de cache', async () => {
56
+ const first = await service.getProvider();
57
+ const second = await service.getProvider();
58
+
59
+ expect(second).toBe(first);
60
+ expect(createSpy).toHaveBeenCalledTimes(1);
61
+ expect(deps.prisma.integration_profile.findUnique).toHaveBeenCalledTimes(1);
62
+ expect(deps.prisma.file_provider.findFirst).toHaveBeenCalledTimes(1);
63
+ });
64
+
65
+ it('mantém o providerId ao servir do cache (usado no registro do arquivo)', async () => {
66
+ await service.getProvider();
67
+ (service as any).providerId = undefined;
68
+
69
+ await service.getProvider();
70
+
71
+ expect((service as any).providerId).toBe(7);
72
+ });
73
+
74
+ it('deduplica resoluções simultâneas (lote de uploads paralelos)', async () => {
75
+ const results = await Promise.all(
76
+ Array.from({ length: 20 }, () => service.getProvider()),
77
+ );
78
+
79
+ expect(createSpy).toHaveBeenCalledTimes(1);
80
+ expect(new Set(results).size).toBe(1);
81
+ });
82
+
83
+ it('não guarda resolução com erro e volta a tentar na chamada seguinte', async () => {
84
+ deps.setting.getSettingValues.mockResolvedValueOnce({
85
+ 'file-storage-profile-id': '',
86
+ } as never);
87
+
88
+ await expect(service.getProvider()).rejects.toThrow(
89
+ 'No file storage profile configured',
90
+ );
91
+
92
+ await expect(service.getProvider()).resolves.toEqual({
93
+ name: 'spaces-provider',
94
+ });
95
+ });
96
+
97
+ it('reresolve depois que a janela de cache expira', async () => {
98
+ await service.getProvider();
99
+ (service as any).cachedProvider.expiresAt = Date.now() - 1;
100
+
101
+ await service.getProvider();
102
+
103
+ expect(createSpy).toHaveBeenCalledTimes(2);
104
+ });
105
+ });
@@ -45,11 +45,31 @@ import { ImageOptimizationService } from './image-optimization.service';
45
45
  import { AbstractProvider } from './provider/abstract.provider';
46
46
  import { ProviderFactory } from './provider/provider.factory';
47
47
 
48
+ type ResolvedProvider = {
49
+ provider: AbstractProvider;
50
+ providerId: number;
51
+ expiresAt: number;
52
+ };
53
+
54
+ /**
55
+ * Resolver o provider custa 3 queries (setting + integration_profile, que ainda decifra o
56
+ * config, + file_provider) e reconstrói o client de storage a cada arquivo. Em upload em
57
+ * massa — segmentos HLS, frames, pacotes SCORM — isso vira milhares de round-trips em
58
+ * rajadas paralelas e é o que estoura o pool de conexões durante a conversão de vídeo.
59
+ * A janela curta mantém a troca de perfil de storage praticamente imediata.
60
+ */
61
+ const PROVIDER_CACHE_TTL_MS = Math.max(
62
+ 0,
63
+ Number(process.env.FILE_PROVIDER_CACHE_TTL_MS ?? 30_000),
64
+ );
65
+
48
66
  @Injectable()
49
67
  export class FileService implements OnModuleInit {
50
68
  private readonly logger = new Logger(FileService.name);
51
69
  private providerId: number | undefined;
52
70
  private mimetypes: Record<string, number> = {};
71
+ private cachedProvider: ResolvedProvider | null = null;
72
+ private providerResolution: Promise<AbstractProvider> | null = null;
53
73
 
54
74
  private resolveProviderPath(file: { location: string; path: string }): string {
55
75
  // Supports legacy basename-only values while prioritizing full provider keys.
@@ -103,6 +123,26 @@ export class FileService implements OnModuleInit {
103
123
  }
104
124
 
105
125
  async getProvider(): Promise<AbstractProvider> {
126
+ const cached = this.cachedProvider;
127
+ if (cached && cached.expiresAt > Date.now()) {
128
+ this.providerId = cached.providerId;
129
+ return cached.provider;
130
+ }
131
+
132
+ // Uploads paralelos (lotes de segmentos HLS) chegam aqui juntos; sem esta deduplicação
133
+ // cada um dispara o mesmo conjunto de queries em vez de aproveitar a primeira resolução.
134
+ if (this.providerResolution) {
135
+ return this.providerResolution;
136
+ }
137
+
138
+ this.providerResolution = this.resolveProvider().finally(() => {
139
+ this.providerResolution = null;
140
+ });
141
+
142
+ return this.providerResolution;
143
+ }
144
+
145
+ private async resolveProvider(): Promise<AbstractProvider> {
106
146
  const settings = await this.settingService.getSettingValues(['file-storage-profile-id']);
107
147
  const profileSlug = String(settings['file-storage-profile-id'] ?? '').trim();
108
148
 
@@ -143,7 +183,17 @@ export class FileService implements OnModuleInit {
143
183
  }
144
184
 
145
185
  this.providerId = providerData.id;
146
- return await ProviderFactory.create(enumProvider, config, this.jwtService);
186
+ const provider = await ProviderFactory.create(enumProvider, config, this.jwtService);
187
+
188
+ if (PROVIDER_CACHE_TTL_MS > 0) {
189
+ this.cachedProvider = {
190
+ provider,
191
+ providerId: providerData.id,
192
+ expiresAt: Date.now() + PROVIDER_CACHE_TTL_MS,
193
+ };
194
+ }
195
+
196
+ return provider;
147
197
  }
148
198
 
149
199
  async getMimeType(mimetype: string) {
@@ -430,6 +480,10 @@ export class FileService implements OnModuleInit {
430
480
  destination: string,
431
481
  fileBuffer: MulterFile,
432
482
  resize?: { maxWidth?: number; maxHeight?: number },
483
+ // Escape hatch para chamadores INTERNOS que já validaram por conta própria —
484
+ // o mesmo par de flags que `uploadFromPath` sempre teve. O FileController não
485
+ // repassa este argumento, então não há como acioná-lo por HTTP.
486
+ options?: { skipMimeValidation?: boolean; skipSizeValidation?: boolean },
433
487
  ) {
434
488
 
435
489
  if (!fileBuffer) {
@@ -442,13 +496,16 @@ export class FileService implements OnModuleInit {
442
496
 
443
497
  const provider = await this.getProvider();
444
498
 
445
- if (!(await this.acceptMimetypes(fileBuffer.mimetype))) {
499
+ if (
500
+ !options?.skipMimeValidation &&
501
+ !(await this.acceptMimetypes(fileBuffer.mimetype))
502
+ ) {
446
503
  throw new BadRequestException(
447
504
  `Invalid file type: ${fileBuffer.mimetype}`,
448
505
  );
449
506
  }
450
507
 
451
- if (!(await this.maxFileSize(fileBuffer.size))) {
508
+ if (!options?.skipSizeValidation && !(await this.maxFileSize(fileBuffer.size))) {
452
509
  throw new BadRequestException(`File too large: ${fileBuffer.size} bytes`);
453
510
  }
454
511
 
@@ -0,0 +1,205 @@
1
+ import { afterAll, beforeEach, describe, expect, it, jest } from '@jest/globals';
2
+ import {
3
+ INCIDENT_NOTIFY_SOURCE,
4
+ IncidentNotifierService,
5
+ type NotifiableIncident,
6
+ } from './incident-notifier.service';
7
+
8
+ const incident = (overrides: Partial<NotifiableIncident> = {}): NotifiableIncident => ({
9
+ id: 1,
10
+ source: 'core.mail',
11
+ code: 'mail_send_failed',
12
+ severity: 'critical',
13
+ message: 'SMTP timeout',
14
+ occurrences: 1,
15
+ context: { slug: 'auth-login-new-device' },
16
+ notifiedAt: null,
17
+ reason: 'created',
18
+ ...overrides,
19
+ });
20
+
21
+ const baseSettings = {
22
+ 'incident.notify-enabled': 'true',
23
+ 'incident.notify-min-severity': 'critical',
24
+ 'incident.notify-cooldown-minutes': '60',
25
+ 'incident.notify-email-to': 'ops@hcode.com.br',
26
+ 'incident.notify-whatsapp-profile': '',
27
+ 'incident.notify-whatsapp-phone-number-id': '',
28
+ 'incident.notify-whatsapp-to': '',
29
+ 'incident.notify-whatsapp-template': '',
30
+ 'incident.notify-whatsapp-template-language': 'pt_BR',
31
+ };
32
+
33
+ const makeDeps = (settings: Record<string, unknown> = {}) => ({
34
+ prisma: {
35
+ system_incident: { update: jest.fn(async () => ({})) },
36
+ integration_profile: {
37
+ findUnique: jest.fn(async () => ({
38
+ config: { access_token: 'token', graph_api_version: 'v21.0' },
39
+ })),
40
+ },
41
+ },
42
+ setting: { getSettingValues: jest.fn(async () => ({ ...baseSettings, ...settings })) },
43
+ mail: { sendRawMail: jest.fn(async () => undefined) },
44
+ });
45
+
46
+ const makeService = (deps: any) =>
47
+ new IncidentNotifierService(deps.prisma as any, deps.setting as any, deps.mail as any);
48
+
49
+ describe('IncidentNotifierService.notify', () => {
50
+ const fetchOriginal = global.fetch;
51
+
52
+ beforeEach(() => {
53
+ jest.clearAllMocks();
54
+ global.fetch = jest.fn(async () => ({ ok: true, json: async () => ({}) })) as any;
55
+ });
56
+
57
+ afterAll(() => {
58
+ global.fetch = fetchOriginal;
59
+ });
60
+
61
+ describe('guardas', () => {
62
+ it('NUNCA avisa sobre falha do próprio aviso — seria laço infinito', async () => {
63
+ const deps = makeDeps();
64
+ await makeService(deps).notify(incident({ source: INCIDENT_NOTIFY_SOURCE }));
65
+
66
+ expect(deps.setting.getSettingValues).not.toHaveBeenCalled();
67
+ expect(deps.mail.sendRawMail).not.toHaveBeenCalled();
68
+ });
69
+
70
+ it('respeita o kill switch', async () => {
71
+ const deps = makeDeps({ 'incident.notify-enabled': 'false' });
72
+ await makeService(deps).notify(incident());
73
+
74
+ expect(deps.mail.sendRawMail).not.toHaveBeenCalled();
75
+ });
76
+
77
+ it('ignora severidade abaixo do mínimo', async () => {
78
+ const deps = makeDeps({ 'incident.notify-min-severity': 'critical' });
79
+ await makeService(deps).notify(incident({ severity: 'warning' }));
80
+
81
+ expect(deps.mail.sendRawMail).not.toHaveBeenCalled();
82
+ });
83
+
84
+ it('avisa quando a severidade está acima do mínimo', async () => {
85
+ const deps = makeDeps({ 'incident.notify-min-severity': 'warning' });
86
+ await makeService(deps).notify(incident({ severity: 'error' }));
87
+
88
+ expect(deps.mail.sendRawMail).toHaveBeenCalled();
89
+ });
90
+
91
+ it('nunca lança, mesmo com o e-mail fora do ar', async () => {
92
+ const deps = makeDeps();
93
+ deps.mail.sendRawMail = jest.fn(async () => {
94
+ throw new Error('SMTP caiu');
95
+ });
96
+
97
+ await expect(makeService(deps).notify(incident())).resolves.toBeUndefined();
98
+ });
99
+ });
100
+
101
+ describe('cooldown', () => {
102
+ it('segura aviso repetido dentro da janela', async () => {
103
+ const deps = makeDeps();
104
+ const agora = new Date();
105
+ await makeService(deps).notify(incident({ notifiedAt: agora }));
106
+
107
+ expect(deps.mail.sendRawMail).not.toHaveBeenCalled();
108
+ });
109
+
110
+ it('volta a avisar depois da janela', async () => {
111
+ const deps = makeDeps({ 'incident.notify-cooldown-minutes': '30' });
112
+ const antigo = new Date(Date.now() - 60 * 60_000);
113
+ await makeService(deps).notify(incident({ notifiedAt: antigo }));
114
+
115
+ expect(deps.mail.sendRawMail).toHaveBeenCalled();
116
+ });
117
+
118
+ it('reabertura ignora o cooldown — foi dado como resolvido e voltou', async () => {
119
+ const deps = makeDeps();
120
+ await makeService(deps).notify(incident({ notifiedAt: new Date(), reason: 'reopened' }));
121
+
122
+ expect(deps.mail.sendRawMail).toHaveBeenCalled();
123
+ });
124
+ });
125
+
126
+ describe('e-mail', () => {
127
+ it('envia para cada destinatário e marca notified_at', async () => {
128
+ const deps = makeDeps({ 'incident.notify-email-to': 'a@x.com, b@x.com' });
129
+ await makeService(deps).notify(incident());
130
+
131
+ expect(deps.mail.sendRawMail).toHaveBeenCalledTimes(2);
132
+ const [args] = deps.mail.sendRawMail.mock.calls[0] as [any];
133
+ expect(args.subject).toContain('CRITICAL');
134
+ expect(args.subject).toContain('core.mail');
135
+ expect(deps.prisma.system_incident.update).toHaveBeenCalled();
136
+ });
137
+
138
+ it('não marca notified_at quando nenhum canal está configurado', async () => {
139
+ const deps = makeDeps({ 'incident.notify-email-to': '' });
140
+ await makeService(deps).notify(incident());
141
+
142
+ expect(deps.prisma.system_incident.update).not.toHaveBeenCalled();
143
+ });
144
+ });
145
+
146
+ describe('whatsapp', () => {
147
+ const whatsappSettings = {
148
+ 'incident.notify-email-to': '',
149
+ 'incident.notify-whatsapp-profile': 'meta-oficial',
150
+ 'incident.notify-whatsapp-phone-number-id': '123456',
151
+ 'incident.notify-whatsapp-to': '+55 (11) 99999-9999',
152
+ };
153
+
154
+ it('envia template aprovado quando configurado', async () => {
155
+ const deps = makeDeps({
156
+ ...whatsappSettings,
157
+ 'incident.notify-whatsapp-template': 'alerta_incidente',
158
+ });
159
+ await makeService(deps).notify(incident());
160
+
161
+ const [url, options] = (global.fetch as any).mock.calls[0];
162
+ expect(url).toContain('/123456/messages');
163
+ const body = JSON.parse(options.body);
164
+ expect(body.type).toBe('template');
165
+ expect(body.template.name).toBe('alerta_incidente');
166
+ // Numero normalizado para digitos E.164.
167
+ expect(body.to).toBe('5511999999999');
168
+ });
169
+
170
+ it('cai para texto livre sem template — só entrega na janela de 24h', async () => {
171
+ const deps = makeDeps(whatsappSettings);
172
+ await makeService(deps).notify(incident());
173
+
174
+ const [, options] = (global.fetch as any).mock.calls[0];
175
+ expect(JSON.parse(options.body).type).toBe('text');
176
+ });
177
+
178
+ it('não marca notified_at quando a Meta recusa', async () => {
179
+ const deps = makeDeps(whatsappSettings);
180
+ global.fetch = jest.fn(async () => ({
181
+ ok: false,
182
+ status: 400,
183
+ json: async () => ({ error: { message: 'fora da janela' } }),
184
+ })) as any;
185
+
186
+ await makeService(deps).notify(incident());
187
+ expect(deps.prisma.system_incident.update).not.toHaveBeenCalled();
188
+ });
189
+
190
+ it('não tenta enviar sem perfil de integração', async () => {
191
+ const deps = makeDeps({ ...whatsappSettings, 'incident.notify-whatsapp-profile': '' });
192
+ await makeService(deps).notify(incident());
193
+
194
+ expect(global.fetch).not.toHaveBeenCalled();
195
+ });
196
+
197
+ it('não tenta enviar quando o perfil não existe', async () => {
198
+ const deps = makeDeps(whatsappSettings);
199
+ deps.prisma.integration_profile.findUnique = jest.fn(async () => null);
200
+
201
+ await makeService(deps).notify(incident());
202
+ expect(global.fetch).not.toHaveBeenCalled();
203
+ });
204
+ });
205
+ });