@hed-hog/core 0.0.386 → 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 (556) 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 +26 -10
  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 +35 -9
  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 +27 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +31 -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 +12 -2
  146. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  147. package/dist/integration-profile/integration-profile.service.d.ts +28 -2
  148. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  149. package/dist/integration-profile/integration-profile.service.js +105 -31
  150. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  151. package/dist/integration-profile/integration-profile.utils.d.ts +31 -1
  152. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  153. package/dist/integration-profile/integration-profile.utils.js +35 -4
  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 +24 -17
  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 +34 -21
  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/webhook-integration/webhook-integration.controller.d.ts +5 -8
  361. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  362. package/dist/webhook-integration/webhook-integration.controller.js +31 -8
  363. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  364. package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
  365. package/dist/webhook-integration/webhook-integration.module.js +5 -0
  366. package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
  367. package/dist/webhook-integration/webhook-integration.service.d.ts +33 -1
  368. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  369. package/dist/webhook-integration/webhook-integration.service.js +109 -4
  370. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  371. package/dist/webhook-integration/webhook-protocol.registry.d.ts +63 -0
  372. package/dist/webhook-integration/webhook-protocol.registry.d.ts.map +1 -0
  373. package/dist/webhook-integration/webhook-protocol.registry.js +51 -0
  374. package/dist/webhook-integration/webhook-protocol.registry.js.map +1 -0
  375. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
  376. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
  377. package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
  378. package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
  379. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
  380. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
  381. package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
  382. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
  383. package/hedhog/data/integration_provider.yaml +16 -0
  384. package/hedhog/data/mail.yaml +88 -61
  385. package/hedhog/data/mail_layout.yaml +188 -0
  386. package/hedhog/data/menu.yaml +67 -3
  387. package/hedhog/data/route.yaml +135 -0
  388. package/hedhog/data/setting_group.yaml +139 -1
  389. package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
  390. package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
  391. package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
  392. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
  393. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
  394. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
  395. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
  396. package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
  397. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
  398. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
  399. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
  400. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
  401. package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
  402. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
  403. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
  404. package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
  405. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +169 -92
  406. package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
  407. package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
  408. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
  409. package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
  410. package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
  411. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
  412. package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
  413. package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
  414. package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
  415. package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
  416. package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
  417. package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
  418. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
  419. package/hedhog/frontend/messages/en.json +521 -3
  420. package/hedhog/frontend/messages/pt.json +521 -3
  421. package/hedhog/table/ai_agent.yaml +1 -0
  422. package/hedhog/table/ai_instruction.yaml +15 -0
  423. package/hedhog/table/leaked_password.yaml +18 -0
  424. package/hedhog/table/mail_layout.yaml +35 -0
  425. package/hedhog/table/mail_var.yaml +4 -0
  426. package/hedhog/table/setting.yaml +1 -0
  427. package/hedhog/table/system_incident.yaml +59 -0
  428. package/hedhog/table/user_presence.yaml +36 -0
  429. package/hedhog/table/webhook_integration.yaml +64 -43
  430. package/package.json +8 -4
  431. package/src/access-log/access-log.interceptor.ts +4 -2
  432. package/src/ai/ai-attachment.fragments.spec.ts +319 -0
  433. package/src/ai/ai-attachment.fragments.ts +35 -0
  434. package/src/ai/ai.prompts.ts +38 -0
  435. package/src/ai/ai.service.spec.ts +280 -0
  436. package/src/ai/ai.service.ts +338 -82
  437. package/src/ai/dto/chat.dto.ts +33 -3
  438. package/src/ai/dto/create-agent.dto.ts +2 -2
  439. package/src/ai/dto/update-agent.dto.ts +2 -2
  440. package/src/ai-instruction/ai-instruction.controller.ts +40 -9
  441. package/src/ai-instruction/ai-instruction.module.ts +13 -2
  442. package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
  443. package/src/ai-instruction/ai-instruction.service.ts +661 -62
  444. package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
  445. package/src/ai-instruction/ai-prompt-registry.ts +87 -0
  446. package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
  447. package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
  448. package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
  449. package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
  450. package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
  451. package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
  452. package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
  453. package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
  454. package/src/auth/auth.controller.ts +33 -6
  455. package/src/auth/auth.service.spec.ts +3 -1
  456. package/src/auth/auth.service.ts +103 -37
  457. package/src/captcha/captcha.module.ts +10 -0
  458. package/src/captcha/captcha.service.spec.ts +210 -0
  459. package/src/captcha/captcha.service.ts +191 -0
  460. package/src/challenge/challenge.service.spec.ts +39 -4
  461. package/src/challenge/challenge.service.ts +72 -17
  462. package/src/core.module.ts +27 -1
  463. package/src/file/file.service.spec.ts +105 -0
  464. package/src/file/file.service.ts +60 -3
  465. package/src/incident/incident-notifier.service.spec.ts +205 -0
  466. package/src/incident/incident-notifier.service.ts +241 -0
  467. package/src/incident/incident.controller.ts +38 -0
  468. package/src/incident/incident.module.ts +19 -0
  469. package/src/incident/incident.service.spec.ts +150 -0
  470. package/src/incident/incident.service.ts +209 -0
  471. package/src/index.ts +38 -0
  472. package/src/integration-profile/dto/test.dto.ts +19 -0
  473. package/src/integration-profile/integration-profile.controller.ts +10 -1
  474. package/src/integration-profile/integration-profile.module.spec.ts +51 -0
  475. package/src/integration-profile/integration-profile.module.ts +23 -4
  476. package/src/integration-profile/integration-profile.secrets.ts +12 -2
  477. package/src/integration-profile/integration-profile.service.spec.ts +279 -0
  478. package/src/integration-profile/integration-profile.service.ts +132 -29
  479. package/src/integration-profile/integration-profile.utils.spec.ts +97 -0
  480. package/src/integration-profile/integration-profile.utils.ts +79 -3
  481. package/src/integration-profile/testers/ai.testers.ts +165 -0
  482. package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
  483. package/src/integration-profile/testers/captcha.testers.ts +139 -0
  484. package/src/integration-profile/testers/email.testers.ts +161 -0
  485. package/src/integration-profile/testers/http-probe.spec.ts +153 -0
  486. package/src/integration-profile/testers/http-probe.ts +171 -0
  487. package/src/integration-profile/testers/index.ts +30 -0
  488. package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
  489. package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
  490. package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
  491. package/src/integration-profile/testers/integration-tester.types.ts +61 -0
  492. package/src/integration-profile/testers/messaging.testers.ts +102 -0
  493. package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
  494. package/src/integration-profile/testers/oauth.testers.ts +305 -0
  495. package/src/integration-profile/testers/payment.testers.ts +185 -0
  496. package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
  497. package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
  498. package/src/integration-profile/testers/storage.testers.ts +226 -0
  499. package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
  500. package/src/language/en.json +4 -2
  501. package/src/language/pt.json +4 -2
  502. package/src/leaked-password/README.md +83 -0
  503. package/src/leaked-password/leaked-password.controller.ts +52 -0
  504. package/src/leaked-password/leaked-password.module.ts +18 -0
  505. package/src/leaked-password/leaked-password.service.ts +242 -0
  506. package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
  507. package/src/leaked-password/seed/common-passwords.txt +335 -0
  508. package/src/mail/dto/preview.dto.ts +50 -0
  509. package/src/mail/dto/send.dto.ts +14 -1
  510. package/src/mail/mail-template.spec.ts +197 -0
  511. package/src/mail/mail.controller.ts +9 -2
  512. package/src/mail/mail.service.spec.ts +116 -1
  513. package/src/mail/mail.service.ts +118 -12
  514. package/src/mail-layout/dto/update.dto.ts +19 -0
  515. package/src/mail-layout/mail-layout.controller.ts +47 -0
  516. package/src/mail-layout/mail-layout.module.ts +22 -0
  517. package/src/mail-layout/mail-layout.service.ts +94 -0
  518. package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
  519. package/src/mcp-chat/mcp-chat.service.ts +122 -26
  520. package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
  521. package/src/oauth/oauth-token-broker.service.ts +363 -0
  522. package/src/oauth/oauth.module.ts +3 -1
  523. package/src/oauth/oauth.service.ts +8 -2
  524. package/src/pdf/pdf.service.ts +75 -0
  525. package/src/presence/presence.controller.ts +29 -0
  526. package/src/presence/presence.listener.ts +53 -0
  527. package/src/presence/presence.module.ts +19 -0
  528. package/src/presence/presence.service.spec.ts +97 -0
  529. package/src/presence/presence.service.ts +160 -0
  530. package/src/profile/dto/delete-account.dto.ts +11 -0
  531. package/src/profile/events/profile-account-deleted.event.ts +13 -0
  532. package/src/profile/profile.controller.ts +52 -36
  533. package/src/profile/profile.service.ts +143 -41
  534. package/src/realtime/realtime.gateway.ts +138 -0
  535. package/src/realtime/realtime.module.ts +16 -0
  536. package/src/realtime/realtime.service.spec.ts +50 -0
  537. package/src/realtime/realtime.service.ts +187 -0
  538. package/src/redis/redis-pubsub.ts +179 -0
  539. package/src/setting/dto/create.dto.ts +13 -2
  540. package/src/setting/setting.service.spec.ts +56 -0
  541. package/src/setting/setting.service.ts +29 -1
  542. package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
  543. package/src/user/dto/query-user-mail-list.dto.ts +10 -0
  544. package/src/user/user-credential.util.ts +35 -0
  545. package/src/user/user.controller.ts +17 -2
  546. package/src/user/user.service.spec.ts +153 -0
  547. package/src/user/user.service.ts +255 -12
  548. package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
  549. package/src/validators/service-locator.ts +15 -0
  550. package/src/webhook-integration/webhook-integration.controller.ts +40 -2
  551. package/src/webhook-integration/webhook-integration.module.ts +5 -0
  552. package/src/webhook-integration/webhook-integration.service.ts +133 -0
  553. package/src/webhook-integration/webhook-protocol.registry.spec.ts +70 -0
  554. package/src/webhook-integration/webhook-protocol.registry.ts +93 -0
  555. package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
  556. package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
@@ -5,19 +5,26 @@ import {
5
5
  BadRequestException,
6
6
  Inject,
7
7
  Injectable,
8
+ Logger,
8
9
  NotFoundException,
9
10
  forwardRef,
10
11
  } from '@nestjs/common';
11
12
  import * as pako from 'pako';
12
- import { buildMailConfigFromIntegration } from './integration-profile.utils';
13
13
  import { CreateDTO } from './dto/create.dto';
14
14
  import {
15
15
  ConflictResolutionDTO,
16
16
  ImportProfileItemDTO,
17
17
  } from './dto/import-confirm.dto';
18
+ import { TestDTO } from './dto/test.dto';
18
19
  import { UpdateDTO } from './dto/update.dto';
19
20
  import { IntegrationCredentialCryptoService } from './integration-credential-crypto.service';
20
21
  import { getSensitiveConfigKeys } from './integration-profile.secrets';
22
+ import { sanitizeTesterError } from './testers/http-probe';
23
+ import { IntegrationTesterRegistry } from './testers/integration-tester.registry';
24
+ import {
25
+ INTEGRATION_TEST_TIMEOUT_MS,
26
+ IntegrationTestOutcome,
27
+ } from './testers/integration-tester.types';
21
28
 
22
29
  type IntegrationProfileExportItem = {
23
30
  slug: string;
@@ -55,6 +62,8 @@ type InvalidImportItem = {
55
62
 
56
63
  @Injectable()
57
64
  export class IntegrationProfileService {
65
+ private readonly logger = new Logger(IntegrationProfileService.name);
66
+
58
67
  constructor(
59
68
  @Inject(forwardRef(() => PrismaService))
60
69
  private readonly prismaService: PrismaService,
@@ -62,6 +71,8 @@ export class IntegrationProfileService {
62
71
  private readonly paginationService: PaginationService,
63
72
  @Inject(forwardRef(() => IntegrationCredentialCryptoService))
64
73
  private readonly credentialCrypto: IntegrationCredentialCryptoService,
74
+ @Inject(forwardRef(() => IntegrationTesterRegistry))
75
+ private readonly testerRegistry: IntegrationTesterRegistry,
65
76
  ) {}
66
77
 
67
78
  async listTypes() {
@@ -430,7 +441,14 @@ export class IntegrationProfileService {
430
441
  });
431
442
  }
432
443
 
433
- async test(data: CreateDTO) {
444
+ /**
445
+ * Testa as credenciais de um perfil contra o serviço real, sem salvar.
446
+ *
447
+ * Só despacha: quem sabe falar com cada provider é o `IntegrationTester` registrado
448
+ * no `IntegrationTesterRegistry`. Funciona tanto na edição (herda os segredos
449
+ * armazenados no lugar da máscara) quanto na criação de um perfil ainda inexistente.
450
+ */
451
+ async test(data: TestDTO) {
434
452
  await this.validateTypeAndProvider(data.type_id, data.provider_id);
435
453
 
436
454
  const provider = await this.prismaService.integration_provider.findUnique({
@@ -451,17 +469,22 @@ export class IntegrationProfileService {
451
469
  );
452
470
  }
453
471
 
454
- if (provider.integration_type.slug !== 'email') {
472
+ const typeSlug = provider.integration_type.slug;
473
+ const slug = data.slug.trim();
474
+
475
+ const tester = this.testerRegistry.find(provider.slug);
476
+ if (!tester) {
455
477
  throw new BadRequestException(
456
- 'Integration profile test is only available for email type.',
478
+ `Connection test is not available for provider "${provider.slug}".`,
457
479
  );
458
480
  }
459
481
 
460
482
  // "Deixe em branco para manter": ao testar na edição, herda os segredos já
461
483
  // armazenados (decifrados pelo middleware) para os campos vazios/mascarados.
484
+ // Resolve por id quando ele veio: o slug é editável e pode ter mudado no form.
462
485
  let effectiveConfig = (data.config as Record<string, unknown>) ?? null;
463
486
  const stored = await this.prismaService.integration_profile.findUnique({
464
- where: { slug: data.slug.trim() },
487
+ where: data.profile_id ? { id: data.profile_id } : { slug },
465
488
  select: { config: true },
466
489
  });
467
490
  if (stored?.config) {
@@ -472,42 +495,122 @@ export class IntegrationProfileService {
472
495
  ) as Record<string, unknown>;
473
496
  }
474
497
 
475
- // Resend não usa SMTP/from_email: valida credenciais/domínio próprios.
476
- if (provider.slug === 'resend') {
477
- const resendCfg = (effectiveConfig as Record<string, unknown> | null) ?? {};
478
- const apiToken = String(resendCfg.api_token ?? '').trim();
479
- const domain = String(resendCfg.domain ?? '').trim();
480
-
481
- if (!apiToken) {
482
- throw new BadRequestException('Resend API token is required.');
483
- }
484
- if (!domain) {
485
- throw new BadRequestException('Resend sending domain is required.');
486
- }
498
+ const config = effectiveConfig ?? {};
499
+ const secretValues = getSensitiveConfigKeys(provider.slug)
500
+ .map((key) => String(config[key] ?? ''))
501
+ .filter((value) => value.length > 0);
487
502
 
488
- return {
489
- success: true,
490
- destination: domain,
503
+ const timeoutMs = tester.timeoutMs ?? INTEGRATION_TEST_TIMEOUT_MS;
504
+ let outcome: IntegrationTestOutcome;
505
+ try {
506
+ // Duplo guarda de tempo: o AbortSignal cobre quem o respeita (fetch/SDKs) e o
507
+ // race cobre quem não respeita (o transporter do nodemailer, por exemplo).
508
+ outcome = await Promise.race([
509
+ tester.test(config, {
510
+ signal: AbortSignal.timeout(timeoutMs),
511
+ typeSlug,
512
+ providerSlug: provider.slug,
513
+ secretValues,
514
+ }),
515
+ this.hardTimeout(timeoutMs + 2_000),
516
+ ]);
517
+ } catch (error) {
518
+ outcome = {
519
+ ok: false,
520
+ error: sanitizeTesterError(error, secretValues),
491
521
  };
492
522
  }
493
523
 
494
- buildMailConfigFromIntegration(provider.slug, effectiveConfig);
495
-
496
- const destination = String(
497
- (effectiveConfig as Record<string, unknown> | null | undefined)?.from_email ??
498
- '',
499
- ).trim();
524
+ const persisted = await this.recordValidation(
525
+ provider.slug,
526
+ slug,
527
+ outcome,
528
+ data.profile_id,
529
+ );
500
530
 
501
- if (!destination) {
502
- throw new BadRequestException('Sender email is required.');
531
+ if (!outcome.ok) {
532
+ this.logger.warn(
533
+ `Integration test failed for provider "${provider.slug}" (profile "${slug}"): ${outcome.error}`,
534
+ );
535
+ throw new BadRequestException(outcome.error || 'Connection test failed.');
503
536
  }
504
537
 
505
538
  return {
539
+ // `success` e `destination` são o contrato legado consumido pela tela de
540
+ // e-mail (core/integrations-webhooks): mantidos com o mesmo significado.
506
541
  success: true,
507
- destination,
542
+ destination: String(config.from_email ?? '').trim() || outcome.info || '',
543
+ ok: true,
544
+ provider: provider.slug,
545
+ ...(outcome.info ? { info: outcome.info } : {}),
546
+ ...(outcome.warning ? { warning: outcome.warning } : {}),
547
+ tested_at: new Date().toISOString(),
548
+ persisted,
508
549
  };
509
550
  }
510
551
 
552
+ /** Rejeita depois de `ms`, para o caso de um tester ignorar o AbortSignal. */
553
+ private hardTimeout(ms: number): Promise<never> {
554
+ return new Promise((_resolve, reject) => {
555
+ const timer = setTimeout(() => {
556
+ const error = new Error('Connection test timed out.');
557
+ error.name = 'TimeoutError';
558
+ reject(error);
559
+ }, ms);
560
+ // Não segura o processo vivo caso o teste termine antes.
561
+ timer.unref?.();
562
+ });
563
+ }
564
+
565
+ /**
566
+ * Grava metadados (não-secretos) da última validação no config do perfil.
567
+ *
568
+ * Devolve se gravou: no fluxo de criação não existe linha ainda, e a UI usa isso
569
+ * para avisar que o resultado não ficou registrado.
570
+ */
571
+ private async recordValidation(
572
+ providerSlug: string,
573
+ slug: string,
574
+ outcome: IntegrationTestOutcome,
575
+ profileId?: number,
576
+ ): Promise<boolean> {
577
+ try {
578
+ const stored = await this.prismaService.integration_profile.findUnique({
579
+ where: profileId ? { id: profileId } : { slug },
580
+ select: { id: true, config: true },
581
+ });
582
+ // Perfil ainda não salvo (teste no fluxo de criação): nada a registrar.
583
+ if (!stored) return false;
584
+
585
+ // Parte de `stored.config`, NUNCA do config recebido: o que o usuário digitou
586
+ // e ainda não salvou não pode ser persistido de carona num teste.
587
+ // `stored.config` vem decifrado pelo middleware; recifra-mos ao gravar.
588
+ const plain = {
589
+ ...((stored.config as Record<string, unknown>) ?? {}),
590
+ last_validated_at: new Date().toISOString(),
591
+ last_validation_status: outcome.ok ? 'ok' : 'error',
592
+ last_error: outcome.ok ? null : (outcome.error ?? null),
593
+ last_validation_info: outcome.ok ? (outcome.info ?? null) : null,
594
+ };
595
+
596
+ await this.prismaService.integration_profile.update({
597
+ where: { id: stored.id },
598
+ data: {
599
+ config: this.credentialCrypto.encryptConfig(providerSlug, plain) as object,
600
+ },
601
+ });
602
+ return true;
603
+ } catch (error) {
604
+ // Falhar ao REGISTRAR não pode transformar um teste bem-sucedido em erro 500.
605
+ this.logger.error(
606
+ `Failed to record validation for profile "${slug}": ${
607
+ error instanceof Error ? error.message : String(error)
608
+ }`,
609
+ );
610
+ return false;
611
+ }
612
+ }
613
+
511
614
  async exportProfiles({
512
615
  ids,
513
616
  includeSecrets = false,
@@ -12,6 +12,8 @@ import {
12
12
  buildDigitalOceanConfigFromIntegration,
13
13
  buildKubernetesConfigFromIntegration,
14
14
  buildAiConfigFromIntegration,
15
+ buildWhatsappOfficialConfigFromIntegration,
16
+ DEFAULT_GRAPH_API_VERSION,
15
17
  } from './integration-profile.utils';
16
18
 
17
19
  describe('integration-profile.utils', () => {
@@ -323,10 +325,105 @@ describe('integration-profile.utils', () => {
323
325
  });
324
326
  });
325
327
 
328
+ it('mapeia deepseek com a base URL padrão', () => {
329
+ expect(
330
+ buildAiConfigFromIntegration('deepseek', {
331
+ api_key: 'd',
332
+ model: 'deepseek-reasoner',
333
+ }),
334
+ ).toEqual({
335
+ apiKey: 'd',
336
+ model: 'deepseek-reasoner',
337
+ baseUrl: 'https://api.deepseek.com',
338
+ });
339
+ });
340
+
341
+ it('respeita a base URL informada no perfil deepseek', () => {
342
+ expect(
343
+ buildAiConfigFromIntegration('deepseek', {
344
+ api_key: 'd',
345
+ base_url: 'https://proxy.interno/v1/',
346
+ }),
347
+ ).toEqual({ apiKey: 'd', baseUrl: 'https://proxy.interno/v1' });
348
+ });
349
+
326
350
  it('lança para provider desconhecido', () => {
327
351
  expect(() => buildAiConfigFromIntegration('llama', {})).toThrow(
328
352
  BadRequestException,
329
353
  );
330
354
  });
331
355
  });
356
+
357
+ describe('buildWhatsappOfficialConfigFromIntegration', () => {
358
+ const fullConfig = {
359
+ app_id: '123456',
360
+ app_secret: 'secret',
361
+ business_id: 'BIZ',
362
+ waba_id: 'WABA',
363
+ access_token: 'token',
364
+ graph_api_version: 'v22.0',
365
+ verify_token: 'verify',
366
+ environment: 'test',
367
+ };
368
+
369
+ it('mapeia todos os campos do perfil', () => {
370
+ expect(buildWhatsappOfficialConfigFromIntegration(fullConfig)).toEqual({
371
+ appId: '123456',
372
+ appSecret: 'secret',
373
+ businessId: 'BIZ',
374
+ wabaId: 'WABA',
375
+ accessToken: 'token',
376
+ graphApiVersion: 'v22.0',
377
+ verifyToken: 'verify',
378
+ environment: 'test',
379
+ });
380
+ });
381
+
382
+ it('assume a versão default da Graph API quando ausente ou vazia', () => {
383
+ expect(
384
+ buildWhatsappOfficialConfigFromIntegration({ ...fullConfig, graph_api_version: '' })
385
+ .graphApiVersion,
386
+ ).toBe(DEFAULT_GRAPH_API_VERSION);
387
+ expect(
388
+ buildWhatsappOfficialConfigFromIntegration({}).graphApiVersion,
389
+ ).toBe(DEFAULT_GRAPH_API_VERSION);
390
+ });
391
+
392
+ it('assume production quando o ambiente não é "test"', () => {
393
+ // Default seguro: um ambiente inválido não deve virar sandbox silenciosamente.
394
+ expect(
395
+ buildWhatsappOfficialConfigFromIntegration({ environment: 'qualquer' })
396
+ .environment,
397
+ ).toBe('production');
398
+ expect(
399
+ buildWhatsappOfficialConfigFromIntegration({}).environment,
400
+ ).toBe('production');
401
+ });
402
+
403
+ it('omite business_id quando não informado (é opcional)', () => {
404
+ const result = buildWhatsappOfficialConfigFromIntegration({});
405
+ expect(result.businessId).toBeUndefined();
406
+ });
407
+
408
+ it('não quebra com config nulo e devolve campos vazios', () => {
409
+ expect(buildWhatsappOfficialConfigFromIntegration(null)).toMatchObject({
410
+ appId: '',
411
+ appSecret: '',
412
+ wabaId: '',
413
+ accessToken: '',
414
+ verifyToken: '',
415
+ });
416
+ });
417
+
418
+ it('remove espaços em volta dos segredos (copiar/colar do painel da Meta)', () => {
419
+ const result = buildWhatsappOfficialConfigFromIntegration({
420
+ access_token: ' token ',
421
+ app_secret: ' secret ',
422
+ verify_token: ' verify ',
423
+ });
424
+ expect(result.accessToken).toBe('token');
425
+ expect(result.appSecret).toBe('secret');
426
+ expect(result.verifyToken).toBe('verify');
427
+ });
428
+ });
332
429
  });
@@ -98,6 +98,45 @@ export function getReplyToAddress(config: unknown): string | undefined {
98
98
  return replyToName ? `${replyToName} <${replyToEmail}>` : replyToEmail;
99
99
  }
100
100
 
101
+ // ─── Messaging utilities ──────────────────────────────────────────────────────
102
+
103
+ export const DEFAULT_GRAPH_API_VERSION = 'v21.0';
104
+
105
+ export type WhatsappOfficialConfig = {
106
+ appId: string;
107
+ appSecret: string;
108
+ businessId?: string;
109
+ wabaId: string;
110
+ accessToken: string;
111
+ graphApiVersion: string;
112
+ verifyToken: string;
113
+ environment: 'test' | 'production';
114
+ };
115
+
116
+ /**
117
+ * Maps an integration_profile config JSON to the Meta WhatsApp Cloud API credentials.
118
+ *
119
+ * Os números não vêm daqui: um WABA pode ter vários e cada um tem estado próprio,
120
+ * então eles vivem na tabela whatsapp_phone_number (library whatsapp).
121
+ */
122
+ export function buildWhatsappOfficialConfigFromIntegration(
123
+ config: unknown,
124
+ ): WhatsappOfficialConfig {
125
+ const cfg = (config as Cfg) ?? {};
126
+ const environment = String(cfg.environment ?? 'production').trim();
127
+ return {
128
+ appId: String(cfg.app_id ?? '').trim(),
129
+ appSecret: String(cfg.app_secret ?? '').trim(),
130
+ ...(cfg.business_id ? { businessId: String(cfg.business_id).trim() } : {}),
131
+ wabaId: String(cfg.waba_id ?? '').trim(),
132
+ accessToken: String(cfg.access_token ?? '').trim(),
133
+ graphApiVersion:
134
+ String(cfg.graph_api_version ?? '').trim() || DEFAULT_GRAPH_API_VERSION,
135
+ verifyToken: String(cfg.verify_token ?? '').trim(),
136
+ environment: environment === 'test' ? 'test' : 'production',
137
+ };
138
+ }
139
+
101
140
  // ─── Storage utilities ────────────────────────────────────────────────────────
102
141
 
103
142
  /**
@@ -261,21 +300,58 @@ export function buildKubernetesConfigFromIntegration(
261
300
 
262
301
  // ─── AI utilities ─────────────────────────────────────────────────────────────
263
302
 
264
- /** Maps an integration_profile config JSON to the API key and optional org needed by AI providers. */
303
+ /**
304
+ * Base URL da API do DeepSeek. A API é compatível com o formato OpenAI
305
+ * (`POST {base}/chat/completions`), então os consumidores reaproveitam o mesmo
306
+ * corpo de requisição trocando apenas a URL e a chave.
307
+ */
308
+ export const DEEPSEEK_API_BASE_URL = 'https://api.deepseek.com';
309
+
310
+ /** Modelo usado quando o perfil DeepSeek não define um (`deepseek-reasoner` é o de raciocínio). */
311
+ export const DEEPSEEK_DEFAULT_MODEL = 'deepseek-chat';
312
+
313
+ /** Maps an integration_profile config JSON to the API key and optional org/model/timeout needed by AI providers. */
265
314
  export function buildAiConfigFromIntegration(
266
315
  providerSlug: string,
267
316
  config: unknown,
268
- ): { apiKey: string; organization?: string } {
317
+ ): {
318
+ apiKey: string;
319
+ organization?: string;
320
+ model?: string;
321
+ timeoutMs?: number;
322
+ /** Endpoint OpenAI-compatible do provider (hoje só o DeepSeek usa). */
323
+ baseUrl?: string;
324
+ } {
269
325
  const cfg = (config as Cfg) ?? {};
326
+ const model = String(cfg.model ?? '').trim() || undefined;
327
+ const parsedTimeout = Number(cfg.timeout_ms);
328
+ const timeoutMs = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : undefined;
329
+
270
330
  switch (providerSlug.toLowerCase()) {
271
331
  case 'openai':
272
332
  return {
273
333
  apiKey: String(cfg.api_key ?? ''),
274
334
  ...(cfg.organization ? { organization: String(cfg.organization) } : {}),
335
+ ...(model ? { model } : {}),
336
+ ...(timeoutMs ? { timeoutMs } : {}),
337
+ };
338
+ case 'deepseek':
339
+ return {
340
+ apiKey: String(cfg.api_key ?? ''),
341
+ ...(model ? { model } : {}),
342
+ ...(timeoutMs ? { timeoutMs } : {}),
343
+ baseUrl:
344
+ String(cfg.base_url ?? '')
345
+ .trim()
346
+ .replace(/\/+$/, '') || DEEPSEEK_API_BASE_URL,
275
347
  };
276
348
  case 'gemini':
277
349
  case 'claude':
278
- return { apiKey: String(cfg.api_key ?? '') };
350
+ return {
351
+ apiKey: String(cfg.api_key ?? ''),
352
+ ...(model ? { model } : {}),
353
+ ...(timeoutMs ? { timeoutMs } : {}),
354
+ };
279
355
  default:
280
356
  throw new BadRequestException(`Unsupported AI provider: ${providerSlug}`);
281
357
  }
@@ -0,0 +1,165 @@
1
+ import {
2
+ describeHttpError,
3
+ fail,
4
+ pass,
5
+ probeJson,
6
+ requireFields,
7
+ str,
8
+ } from './http-probe';
9
+ import { IntegrationTester } from './integration-tester.types';
10
+
11
+ /**
12
+ * Testadores dos providers de IA e geração de vídeo.
13
+ *
14
+ * Todos listam modelos: é a chamada autenticada mais barata de cada API (não consome
15
+ * token nem gera cobrança) e prova que a chave está ativa.
16
+ */
17
+
18
+ const openAiTester: IntegrationTester = {
19
+ providerSlug: 'openai',
20
+ test: async (config, ctx) => {
21
+ const missing = requireFields(config, [['api_key', 'API key']]);
22
+ if (missing) return missing;
23
+
24
+ const organization = str(config, 'organization');
25
+ const headers: Record<string, string> = {
26
+ Authorization: `Bearer ${String(config.api_key ?? '')}`,
27
+ ...(organization ? { 'OpenAI-Organization': organization } : {}),
28
+ };
29
+
30
+ const result = await probeJson(
31
+ 'https://api.openai.com/v1/models',
32
+ { headers },
33
+ ctx.signal,
34
+ );
35
+
36
+ if (result.status === 401) return fail('Invalid OpenAI API key.');
37
+ if (result.status === 403) {
38
+ return fail('This API key has no permission to list models.');
39
+ }
40
+ if (!result.ok) {
41
+ return fail(describeHttpError(result, 'OpenAI rejected the credentials.'));
42
+ }
43
+
44
+ const models: Array<{ id?: string }> = Array.isArray(result.body?.data)
45
+ ? result.body.data
46
+ : [];
47
+ const wanted = str(config, 'model');
48
+
49
+ // Modelo indisponível para a conta não invalida a chave — o operador só precisa
50
+ // saber antes de descobrir na primeira chamada real.
51
+ if (wanted && !models.some((model) => model.id === wanted)) {
52
+ return pass(
53
+ `OpenAI — ${models.length} model(s) available`,
54
+ `The model "${wanted}" is not available for this account.`,
55
+ );
56
+ }
57
+ return pass(
58
+ `OpenAI — ${models.length} model(s) available${wanted ? ` (${wanted} ok)` : ''}`,
59
+ );
60
+ },
61
+ };
62
+
63
+ const geminiTester: IntegrationTester = {
64
+ providerSlug: 'gemini',
65
+ test: async (config, ctx) => {
66
+ const missing = requireFields(config, [['api_key', 'API key']]);
67
+ if (missing) return missing;
68
+
69
+ const url = `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(
70
+ String(config.api_key ?? ''),
71
+ )}`;
72
+ const result = await probeJson(url, {}, ctx.signal);
73
+
74
+ if (result.status === 400 || result.status === 401 || result.status === 403) {
75
+ return fail('Invalid Gemini API key.');
76
+ }
77
+ if (!result.ok) {
78
+ return fail(describeHttpError(result, 'Google rejected the credentials.'));
79
+ }
80
+
81
+ const models: unknown[] = Array.isArray(result.body?.models)
82
+ ? result.body.models
83
+ : [];
84
+ return pass(`Gemini — ${models.length} model(s) available`);
85
+ },
86
+ };
87
+
88
+ const claudeTester: IntegrationTester = {
89
+ providerSlug: 'claude',
90
+ test: async (config, ctx) => {
91
+ const missing = requireFields(config, [['api_key', 'API key']]);
92
+ if (missing) return missing;
93
+
94
+ const result = await probeJson(
95
+ 'https://api.anthropic.com/v1/models',
96
+ {
97
+ headers: {
98
+ 'x-api-key': String(config.api_key ?? ''),
99
+ 'anthropic-version': '2023-06-01',
100
+ },
101
+ },
102
+ ctx.signal,
103
+ );
104
+
105
+ if (result.status === 401) return fail('Invalid Anthropic API key.');
106
+ if (!result.ok) {
107
+ return fail(describeHttpError(result, 'Anthropic rejected the credentials.'));
108
+ }
109
+
110
+ const models: unknown[] = Array.isArray(result.body?.data) ? result.body.data : [];
111
+ return pass(`Claude — ${models.length} model(s) available`);
112
+ },
113
+ };
114
+
115
+ const deepseekTester: IntegrationTester = {
116
+ providerSlug: 'deepseek',
117
+ test: async (config, ctx) => {
118
+ const missing = requireFields(config, [['api_key', 'API key']]);
119
+ if (missing) return missing;
120
+
121
+ const result = await probeJson(
122
+ 'https://api.deepseek.com/models',
123
+ { headers: { Authorization: `Bearer ${String(config.api_key ?? '')}` } },
124
+ ctx.signal,
125
+ );
126
+
127
+ if (result.status === 401) return fail('Invalid DeepSeek API key.');
128
+ if (!result.ok) {
129
+ return fail(describeHttpError(result, 'DeepSeek rejected the credentials.'));
130
+ }
131
+
132
+ const models: unknown[] = Array.isArray(result.body?.data) ? result.body.data : [];
133
+ return pass(`DeepSeek — ${models.length} model(s) available`);
134
+ },
135
+ };
136
+
137
+ const lumaTester: IntegrationTester = {
138
+ providerSlug: 'luma',
139
+ test: async (config, ctx) => {
140
+ const missing = requireFields(config, [['api_key', 'API key']]);
141
+ if (missing) return missing;
142
+
143
+ const result = await probeJson(
144
+ 'https://api.lumalabs.ai/dream-machine/v1/generations?limit=1',
145
+ { headers: { Authorization: `Bearer ${String(config.api_key ?? '')}` } },
146
+ ctx.signal,
147
+ );
148
+
149
+ if (result.status === 401 || result.status === 403) {
150
+ return fail('Invalid Luma API key.');
151
+ }
152
+ if (!result.ok) {
153
+ return fail(describeHttpError(result, 'Luma rejected the credentials.'));
154
+ }
155
+ return pass('Luma Dream Machine');
156
+ },
157
+ };
158
+
159
+ export const AI_TESTERS: IntegrationTester[] = [
160
+ openAiTester,
161
+ geminiTester,
162
+ claudeTester,
163
+ deepseekTester,
164
+ lumaTester,
165
+ ];