@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
@@ -6,6 +6,7 @@ import {
6
6
  afterEach,
7
7
  jest,
8
8
  } from '@jest/globals';
9
+ import { renderMailTemplate } from '@hed-hog/api-mail';
9
10
  import { BadRequestException } from '@nestjs/common';
10
11
  import { MailService } from './mail.service';
11
12
 
@@ -28,7 +29,8 @@ const makeDeps = () => {
28
29
  const localeService = {};
29
30
  const setting = { getSettingValues: jest.fn(), setValue: jest.fn() };
30
31
  const integrationApi = { subscribe: jest.fn() };
31
- return { prismaService, mailMainService, localeService, setting, integrationApi };
32
+ const incident = { record: jest.fn(), persist: jest.fn() };
33
+ return { prismaService, mailMainService, localeService, setting, integrationApi, incident };
32
34
  };
33
35
 
34
36
  const makeService = (deps = makeDeps()) => ({
@@ -38,6 +40,7 @@ const makeService = (deps = makeDeps()) => ({
38
40
  deps.localeService as any,
39
41
  deps.setting as any,
40
42
  deps.integrationApi as any,
43
+ deps.incident as any,
41
44
  ),
42
45
  deps,
43
46
  });
@@ -254,4 +257,116 @@ describe('MailService', () => {
254
257
  expect(deps.mailMainService.send).not.toHaveBeenCalled();
255
258
  });
256
259
  });
260
+
261
+ describe('preview', () => {
262
+ const LAYOUT_ROW = {
263
+ id: 1,
264
+ wrapper:
265
+ '<html lang="{{lang}}"><body>{{{header}}}<main>{{{content}}}</main>{{{footer}}}</body></html>',
266
+ mail_layout_locale: [
267
+ {
268
+ header: '<h1>{{subject}}</h1>',
269
+ footer: 'Enviado por {{brandName}}',
270
+ locale: { code: 'pt' },
271
+ },
272
+ ],
273
+ };
274
+
275
+ const makePreviewService = () => {
276
+ const { service, deps } = makeService();
277
+ (deps.prismaService as any).mail_layout = {
278
+ findFirst: jest.fn<any>().mockResolvedValue(LAYOUT_ROW),
279
+ };
280
+ deps.setting.getSettingValues.mockResolvedValue({
281
+ 'system-name': 'Acme',
282
+ } as any);
283
+ return { service, deps };
284
+ };
285
+
286
+ it('interpola variáveis e aplica o layout padrão do banco', async () => {
287
+ const { service } = makePreviewService();
288
+
289
+ const { html } = await service.preview('pt', {
290
+ subject: 'Olá {{name}}',
291
+ body: '<p>Bem-vindo, {{name}}</p>',
292
+ variables: { name: 'Bob' },
293
+ });
294
+
295
+ expect(html).toContain('<h1>Olá Bob</h1>');
296
+ expect(html).toContain('<p>Bem-vindo, Bob</p>');
297
+ expect(html).toContain('Enviado por Acme');
298
+ expect(html).toContain('lang="pt"');
299
+ });
300
+
301
+ it('produz exatamente o mesmo corpo que o envio real', async () => {
302
+ // Esta é a asserção que justifica o endpoint: o preview do admin não pode
303
+ // divergir do e-mail que sai. Os dois caminhos passam pelo mesmo
304
+ // interpolateTemplate (inclusive a troca de \n por <br/>) e pelo mesmo
305
+ // renderMailTemplate.
306
+ const { service } = makePreviewService();
307
+
308
+ const subject = 'Olá {{name}}';
309
+ const body = 'Linha 1\nLinha 2 {{name}}';
310
+ const variables = { name: 'Bob' };
311
+
312
+ const { html: previewHtml } = await service.preview('pt', {
313
+ subject,
314
+ body,
315
+ variables,
316
+ });
317
+
318
+ const interpolate = (src: string) =>
319
+ (service as any).interpolateTemplate(src, variables);
320
+ const layout = await (service as any).resolveDefaultLayout('pt');
321
+ const sentHtml = renderMailTemplate({
322
+ subject: interpolate(subject),
323
+ body: interpolate(body),
324
+ layout,
325
+ brandName: 'Acme',
326
+ lang: 'pt',
327
+ });
328
+
329
+ expect(previewHtml).toBe(sentHtml);
330
+ expect(previewHtml).toContain('Linha 1<br/>Linha 2 Bob');
331
+ });
332
+
333
+ it('usa o layout inline enviado pelo editor, sem consultar o banco', async () => {
334
+ const { service, deps } = makePreviewService();
335
+
336
+ const { html } = await service.preview('pt', {
337
+ body: 'corpo',
338
+ layout: {
339
+ wrapper: '<html>[{{{header}}}]{{{content}}}</html>',
340
+ header: 'CABECALHO',
341
+ footer: '',
342
+ },
343
+ });
344
+
345
+ expect(html).toBe('<html>[CABECALHO]corpo</html>');
346
+ expect(
347
+ (deps.prismaService as any).mail_layout.findFirst,
348
+ ).not.toHaveBeenCalled();
349
+ });
350
+
351
+ it('devolve o corpo cru quando use_layout=false', async () => {
352
+ const { service } = makePreviewService();
353
+
354
+ const { html } = await service.preview('pt', {
355
+ body: '<p>cru</p>',
356
+ use_layout: false,
357
+ });
358
+
359
+ expect(html).toBe('<p>cru</p>');
360
+ });
361
+
362
+ it('cai no layout embutido quando não há layout no banco', async () => {
363
+ const { service, deps } = makePreviewService();
364
+ (deps.prismaService as any).mail_layout.findFirst.mockResolvedValue(null);
365
+
366
+ const { html } = await service.preview('pt', { body: '<p>corpo</p>' });
367
+
368
+ expect(html).toContain('<!DOCTYPE html>');
369
+ expect(html).toContain('<p>corpo</p>');
370
+ });
371
+ });
257
372
  });
@@ -1,6 +1,10 @@
1
1
  import { DeleteDTO } from '@hed-hog/api';
2
2
  import { getLocaleText, LocaleService } from '@hed-hog/api-locale';
3
- import { MailService as MailMainService } from '@hed-hog/api-mail';
3
+ import {
4
+ MailLayout,
5
+ MailService as MailMainService,
6
+ renderMailTemplate,
7
+ } from '@hed-hog/api-mail';
4
8
  import { PaginationDTO } from '@hed-hog/api-pagination';
5
9
  import { PrismaService } from '@hed-hog/api-prisma';
6
10
  import {
@@ -21,9 +25,11 @@ import { IntegrationDeveloperApiService } from '../integration/services/integrat
21
25
  import { SettingService } from '../setting/setting.service';
22
26
  import { CreateDTO } from './dto/create.dto';
23
27
  import { ImportDTO } from './dto/import.dto';
28
+ import { PreviewDTO } from './dto/preview.dto';
24
29
  import { SendTemplatedMailDTO } from './dto/send.dto';
25
30
  import { TestMailDTO } from './dto/test-mail.dto';
26
31
  import { UpdateDTO } from './dto/update.dto';
32
+ import { IncidentService } from '../incident/incident.service';
27
33
 
28
34
  @Injectable()
29
35
  export class MailService implements OnModuleInit {
@@ -43,6 +49,8 @@ export class MailService implements OnModuleInit {
43
49
  private readonly setting: SettingService,
44
50
  @Inject(forwardRef(() => IntegrationDeveloperApiService))
45
51
  private readonly integrationApi: IntegrationDeveloperApiService,
52
+ @Inject(forwardRef(() => IncidentService))
53
+ private readonly incident: IncidentService,
46
54
  ) { }
47
55
 
48
56
  onModuleInit(): void {
@@ -389,22 +397,33 @@ export class MailService implements OnModuleInit {
389
397
 
390
398
  async sendTemplatedMail(
391
399
  locale: string,
392
- { email, slug, variables }: SendTemplatedMailDTO,
400
+ { email, slug, variables, profileSlug, app }: SendTemplatedMailDTO,
393
401
  ) {
394
402
  const settings = await this.setting.getSettingValues(['configured-mail']);
395
403
 
396
404
  if (!this.isSettingEnabled(settings['configured-mail'])) {
397
405
  this.logger.warn('Mail service is not configured. Aborting sending email.');
406
+ // Aborto silencioso: sem isto, todo e-mail transacional do sistema para
407
+ // de sair e ninguem fica sabendo ate um usuario reclamar.
408
+ this.incident.record({
409
+ source: 'core.mail',
410
+ code: 'mail_not_configured',
411
+ severity: 'critical',
412
+ message: 'Envio de e-mail abortado: a configuracao de e-mail nao esta ativa.',
413
+ context: { slug },
414
+ });
398
415
  return;
399
416
  }
400
417
 
401
418
  try {
402
- const { from } = await this.reloadConfig();
419
+ const { from } = await this.reloadConfig(profileSlug);
403
420
  const localeRecord = await this.getLocaleRecord(locale);
404
421
  const mail = await this.getMailTemplate(slug, localeRecord.id);
405
422
  const { subject, body } = mail.mail_locale[0];
406
- const parsedSubject = this.interpolateTemplate(subject, variables);
407
- const parsedBody = this.interpolateTemplate(body, variables);
423
+ const brandName = await this.mailMainService.getBrandName(app, locale);
424
+ const mergedVariables = { brandName, ...variables };
425
+ const parsedSubject = this.interpolateTemplate(subject, mergedVariables);
426
+ const parsedBody = this.interpolateTemplate(body, mergedVariables);
408
427
 
409
428
  await this.mailMainService.send({
410
429
  to: email,
@@ -412,11 +431,21 @@ export class MailService implements OnModuleInit {
412
431
  subject: parsedSubject,
413
432
  body: parsedBody,
414
433
  mail_id: mail.id,
434
+ locale,
435
+ app,
415
436
  });
416
437
 
417
438
  } catch (error) {
418
439
  this.logger.error('Error sending templated mail:', error);
419
- await this.setting.setValue('configured-mail', 'false');
440
+ // Agrupado por slug: um template quebrado vira um incidente com contador,
441
+ // nao uma linha por destinatario.
442
+ this.incident.record({
443
+ source: 'core.mail',
444
+ code: 'mail_send_failed',
445
+ message: error instanceof Error ? error.message : String(error),
446
+ key: slug,
447
+ context: { slug, locale },
448
+ });
420
449
  }
421
450
  }
422
451
 
@@ -468,6 +497,84 @@ export class MailService implements OnModuleInit {
468
497
  }
469
498
  }
470
499
 
500
+ /**
501
+ * Le o layout padrao direto do banco, sem passar pelo cache do api-mail.
502
+ *
503
+ * O preview tem que refletir o que acabou de ser salvo, entao aqui o cache de
504
+ * 60s atrapalharia em vez de ajudar.
505
+ */
506
+ private async resolveDefaultLayout(
507
+ locale: string,
508
+ ): Promise<MailLayout | null> {
509
+ const layoutRow = await this.prismaService.mail_layout.findFirst({
510
+ where: { is_default: true },
511
+ include: {
512
+ mail_layout_locale: {
513
+ include: { locale: { select: { code: true } } },
514
+ },
515
+ },
516
+ });
517
+
518
+ if (!layoutRow) {
519
+ return null;
520
+ }
521
+
522
+ const translations = layoutRow.mail_layout_locale || [];
523
+ const translation =
524
+ translations.find((t: any) => t.locale?.code === locale) ||
525
+ translations.find((t: any) => t.locale?.code === 'en') ||
526
+ translations[0];
527
+
528
+ return {
529
+ wrapper: layoutRow.wrapper,
530
+ header: translation?.header ?? '',
531
+ footer: translation?.footer ?? '',
532
+ };
533
+ }
534
+
535
+ /**
536
+ * Renderiza exatamente o HTML que sairia no envio.
537
+ *
538
+ * Usa o mesmo `interpolateTemplate` de `sendTemplatedMail` (inclusive a troca
539
+ * de quebras de linha por `<br/>`) e o mesmo `renderMailTemplate`. Qualquer
540
+ * atalho aqui recriaria a divergencia entre o que o admin ve e o que o
541
+ * destinatario recebe.
542
+ */
543
+ async preview(
544
+ locale: string,
545
+ { subject, body, variables, use_layout, layout }: PreviewDTO,
546
+ ): Promise<{ html: string }> {
547
+ const settings = await this.setting.getSettingValues(['system-name']);
548
+ const brandName = settings['system-name'] as string;
549
+ const data = { brandName, ...(variables || {}) };
550
+ const parsedSubject = subject ? this.interpolateTemplate(subject, data) : '';
551
+ const parsedBody = body ? this.interpolateTemplate(body, data) : '';
552
+
553
+ let resolvedLayout: MailLayout | null = null;
554
+
555
+ if (use_layout !== false) {
556
+ resolvedLayout = layout
557
+ ? {
558
+ wrapper: layout.wrapper ?? '',
559
+ header: layout.header ?? '',
560
+ footer: layout.footer ?? '',
561
+ }
562
+ : await this.resolveDefaultLayout(locale);
563
+ }
564
+
565
+ const html = renderMailTemplate({
566
+ subject: parsedSubject,
567
+ body: parsedBody,
568
+ // use_layout === false vira um layout sem wrapper, o que faz o render
569
+ // devolver o corpo cru.
570
+ layout: use_layout === false ? { wrapper: '' } : resolvedLayout,
571
+ brandName,
572
+ lang: locale,
573
+ });
574
+
575
+ return { html };
576
+ }
577
+
471
578
  async sendTestMail(locale: string, {
472
579
  slug,
473
580
  email,
@@ -486,12 +593,10 @@ export class MailService implements OnModuleInit {
486
593
  const { from } = await this.reloadConfig();
487
594
 
488
595
  try {
489
- const parsedSubject = variables
490
- ? this.interpolateTemplate(subject, variables)
491
- : subject;
492
- const parsedBody = variables
493
- ? this.interpolateTemplate(body, variables)
494
- : body;
596
+ const brandName = await this.mailMainService.getBrandName(undefined, locale);
597
+ const mergedVariables = { brandName, ...(variables || {}) };
598
+ const parsedSubject = this.interpolateTemplate(subject, mergedVariables);
599
+ const parsedBody = this.interpolateTemplate(body, mergedVariables);
495
600
 
496
601
  return this.mailMainService.send({
497
602
  to: email,
@@ -499,6 +604,7 @@ export class MailService implements OnModuleInit {
499
604
  body: parsedBody,
500
605
  mail_id: mail.id,
501
606
  from,
607
+ locale,
502
608
  });
503
609
  } catch (error) {
504
610
  this.logger.error('Error sending test mail:', error);
@@ -0,0 +1,19 @@
1
+ import { IsObject, IsOptional, IsString } from 'class-validator';
2
+
3
+ export class UpdateDTO {
4
+ @IsString()
5
+ @IsOptional()
6
+ wrapper?: string;
7
+
8
+ /**
9
+ * Traducoes indexadas pelo CODIGO do locale (`{ pt: { name, header, footer } }`).
10
+ *
11
+ * Codigo e nao id de proposito: o `useApp().locales` do admin so expoe
12
+ * `{ code, name }`, entao qualquer payload baseado em id acabaria adivinhando o
13
+ * id a partir do indice do array. `LocaleService.updateModelWithLocale` resolve
14
+ * o codigo via `getByCode`.
15
+ */
16
+ @IsObject()
17
+ @IsOptional()
18
+ locale?: Record<string, { name?: string; header?: string; footer?: string }>;
19
+ }
@@ -0,0 +1,47 @@
1
+ import { Role } from '@hed-hog/api';
2
+ import { Locale } from '@hed-hog/api-locale';
3
+ import { Pagination } from '@hed-hog/api-pagination';
4
+ import {
5
+ Body,
6
+ Controller,
7
+ Get,
8
+ Inject,
9
+ Param,
10
+ ParseIntPipe,
11
+ Patch,
12
+ forwardRef,
13
+ } from '@nestjs/common';
14
+ import { UpdateDTO } from './dto/update.dto';
15
+ import { MailLayoutService } from './mail-layout.service';
16
+
17
+ /**
18
+ * Controller proprio (e nao `@Get('layout')` dentro de MailController) porque o
19
+ * MailController ja declara `@Get(':id')` com ParseIntPipe: uma rota
20
+ * `/mail/layout` seria capturada por ele e responderia 400.
21
+ */
22
+ @Role()
23
+ @Controller('mail-layout')
24
+ export class MailLayoutController {
25
+ constructor(
26
+ @Inject(forwardRef(() => MailLayoutService))
27
+ private readonly mailLayoutService: MailLayoutService,
28
+ ) {}
29
+
30
+ @Get()
31
+ async list(@Locale() locale, @Pagination() paginationParams) {
32
+ return this.mailLayoutService.list(locale, paginationParams);
33
+ }
34
+
35
+ @Get(':id')
36
+ async get(@Param('id', ParseIntPipe) id: number) {
37
+ return this.mailLayoutService.get(id);
38
+ }
39
+
40
+ @Patch(':id')
41
+ async update(
42
+ @Param('id', ParseIntPipe) id: number,
43
+ @Body() data: UpdateDTO,
44
+ ) {
45
+ return this.mailLayoutService.update(id, data);
46
+ }
47
+ }
@@ -0,0 +1,22 @@
1
+ import { LocaleModule } from '@hed-hog/api-locale';
2
+ import { PaginationModule } from '@hed-hog/api-pagination';
3
+ import { PrismaModule } from '@hed-hog/api-prisma';
4
+ import { forwardRef, Module } from '@nestjs/common';
5
+ import { MailModule } from '../mail/mail.module';
6
+ import { MailLayoutController } from './mail-layout.controller';
7
+ import { MailLayoutService } from './mail-layout.service';
8
+
9
+ @Module({
10
+ imports: [
11
+ // MailModule registra o MailModule global do api-mail, de onde vem o
12
+ // MailService usado para invalidar o cache do layout.
13
+ forwardRef(() => MailModule),
14
+ forwardRef(() => PrismaModule),
15
+ forwardRef(() => PaginationModule),
16
+ forwardRef(() => LocaleModule),
17
+ ],
18
+ controllers: [MailLayoutController],
19
+ providers: [MailLayoutService],
20
+ exports: [MailLayoutService],
21
+ })
22
+ export class MailLayoutModule {}
@@ -0,0 +1,94 @@
1
+ import { LocaleService } from '@hed-hog/api-locale';
2
+ import { MailService as MailMainService } from '@hed-hog/api-mail';
3
+ import { PaginationDTO } from '@hed-hog/api-pagination';
4
+ import { PrismaService } from '@hed-hog/api-prisma';
5
+ import {
6
+ BadRequestException,
7
+ forwardRef,
8
+ Inject,
9
+ Injectable,
10
+ NotFoundException,
11
+ } from '@nestjs/common';
12
+ import { UpdateDTO } from './dto/update.dto';
13
+
14
+ /**
15
+ * Layout base aplicado a todo e-mail transacional do sistema.
16
+ *
17
+ * Modelo de registro unico na pratica (um `is_default`), mas a tabela ja tem
18
+ * `slug` + `is_default` para permitir varios layouts depois sem migration
19
+ * destrutiva.
20
+ */
21
+ @Injectable()
22
+ export class MailLayoutService {
23
+ private readonly modelName = 'mail_layout';
24
+ private readonly foreignKeyName = 'mail_layout_id';
25
+
26
+ constructor(
27
+ @Inject(forwardRef(() => PrismaService))
28
+ private readonly prismaService: PrismaService,
29
+ @Inject(forwardRef(() => LocaleService))
30
+ private readonly localeService: LocaleService,
31
+ @Inject(forwardRef(() => MailMainService))
32
+ private readonly mailMainService: MailMainService,
33
+ ) {}
34
+
35
+ async list(locale: string, paginationParams: PaginationDTO): Promise<any> {
36
+ return this.localeService.listModelWithLocale(
37
+ locale,
38
+ this.modelName,
39
+ paginationParams,
40
+ );
41
+ }
42
+
43
+ async get(id: number): Promise<any> {
44
+ const layout = await this.localeService.getModelWithLocale(
45
+ this.modelName,
46
+ id,
47
+ );
48
+
49
+ if (!layout) {
50
+ throw new NotFoundException(`Mail layout with id ${id} not found.`);
51
+ }
52
+
53
+ return layout;
54
+ }
55
+
56
+ /** Retorna o layout marcado como padrao, que e o que a tela do admin edita. */
57
+ async getDefault(): Promise<any> {
58
+ const row = await this.prismaService.mail_layout.findFirst({
59
+ where: { is_default: true },
60
+ select: { id: true },
61
+ });
62
+
63
+ if (!row) {
64
+ throw new NotFoundException('No default mail layout configured.');
65
+ }
66
+
67
+ return this.get(row.id);
68
+ }
69
+
70
+ async update(id: number, data: UpdateDTO): Promise<any> {
71
+ if (data.wrapper !== undefined && !this.hasContentToken(data.wrapper)) {
72
+ // Um wrapper sem slot de conteudo enviaria e-mails vazios para todo mundo,
73
+ // e a falha so apareceria na caixa do destinatario.
74
+ throw new BadRequestException(
75
+ 'The wrapper must contain a {{{content}}} token.',
76
+ );
77
+ }
78
+
79
+ const updated = await this.localeService.updateModelWithLocale(
80
+ this.modelName,
81
+ this.foreignKeyName,
82
+ id,
83
+ data,
84
+ );
85
+
86
+ this.mailMainService.invalidateLayoutCache();
87
+
88
+ return updated;
89
+ }
90
+
91
+ private hasContentToken(wrapper: string): boolean {
92
+ return wrapper.includes('{{{content}}}') || wrapper.includes('{{content}}');
93
+ }
94
+ }