@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
@@ -5,22 +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 {
13
- buildMailConfigFromIntegration,
14
- buildWhatsappOfficialConfigFromIntegration,
15
- } from './integration-profile.utils';
16
13
  import { CreateDTO } from './dto/create.dto';
17
14
  import {
18
15
  ConflictResolutionDTO,
19
16
  ImportProfileItemDTO,
20
17
  } from './dto/import-confirm.dto';
18
+ import { TestDTO } from './dto/test.dto';
21
19
  import { UpdateDTO } from './dto/update.dto';
22
20
  import { IntegrationCredentialCryptoService } from './integration-credential-crypto.service';
23
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';
24
28
 
25
29
  type IntegrationProfileExportItem = {
26
30
  slug: string;
@@ -58,6 +62,8 @@ type InvalidImportItem = {
58
62
 
59
63
  @Injectable()
60
64
  export class IntegrationProfileService {
65
+ private readonly logger = new Logger(IntegrationProfileService.name);
66
+
61
67
  constructor(
62
68
  @Inject(forwardRef(() => PrismaService))
63
69
  private readonly prismaService: PrismaService,
@@ -65,6 +71,8 @@ export class IntegrationProfileService {
65
71
  private readonly paginationService: PaginationService,
66
72
  @Inject(forwardRef(() => IntegrationCredentialCryptoService))
67
73
  private readonly credentialCrypto: IntegrationCredentialCryptoService,
74
+ @Inject(forwardRef(() => IntegrationTesterRegistry))
75
+ private readonly testerRegistry: IntegrationTesterRegistry,
68
76
  ) {}
69
77
 
70
78
  async listTypes() {
@@ -433,7 +441,14 @@ export class IntegrationProfileService {
433
441
  });
434
442
  }
435
443
 
436
- 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) {
437
452
  await this.validateTypeAndProvider(data.type_id, data.provider_id);
438
453
 
439
454
  const provider = await this.prismaService.integration_provider.findUnique({
@@ -455,17 +470,21 @@ export class IntegrationProfileService {
455
470
  }
456
471
 
457
472
  const typeSlug = provider.integration_type.slug;
458
- if (typeSlug !== 'email' && typeSlug !== 'whatsapp') {
473
+ const slug = data.slug.trim();
474
+
475
+ const tester = this.testerRegistry.find(provider.slug);
476
+ if (!tester) {
459
477
  throw new BadRequestException(
460
- 'Integration profile test is only available for email and whatsapp types.',
478
+ `Connection test is not available for provider "${provider.slug}".`,
461
479
  );
462
480
  }
463
481
 
464
482
  // "Deixe em branco para manter": ao testar na edição, herda os segredos já
465
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.
466
485
  let effectiveConfig = (data.config as Record<string, unknown>) ?? null;
467
486
  const stored = await this.prismaService.integration_profile.findUnique({
468
- where: { slug: data.slug.trim() },
487
+ where: data.profile_id ? { id: data.profile_id } : { slug },
469
488
  select: { config: true },
470
489
  });
471
490
  if (stored?.config) {
@@ -476,143 +495,120 @@ export class IntegrationProfileService {
476
495
  ) as Record<string, unknown>;
477
496
  }
478
497
 
479
- if (typeSlug === 'whatsapp') {
480
- return this.testWhatsappProfile(
481
- provider.slug,
482
- data.slug.trim(),
483
- effectiveConfig,
484
- );
485
- }
486
-
487
- // Resend não usa SMTP/from_email: valida credenciais/domínio próprios.
488
- if (provider.slug === 'resend') {
489
- const resendCfg = (effectiveConfig as Record<string, unknown> | null) ?? {};
490
- const apiToken = String(resendCfg.api_token ?? '').trim();
491
- const domain = String(resendCfg.domain ?? '').trim();
498
+ const config = effectiveConfig ?? {};
499
+ const secretValues = getSensitiveConfigKeys(provider.slug)
500
+ .map((key) => String(config[key] ?? ''))
501
+ .filter((value) => value.length > 0);
492
502
 
493
- if (!apiToken) {
494
- throw new BadRequestException('Resend API token is required.');
495
- }
496
- if (!domain) {
497
- throw new BadRequestException('Resend sending domain is required.');
498
- }
499
-
500
- return {
501
- success: true,
502
- 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),
503
521
  };
504
522
  }
505
523
 
506
- buildMailConfigFromIntegration(provider.slug, effectiveConfig);
507
-
508
- const destination = String(
509
- (effectiveConfig as Record<string, unknown> | null | undefined)?.from_email ??
510
- '',
511
- ).trim();
524
+ const persisted = await this.recordValidation(
525
+ provider.slug,
526
+ slug,
527
+ outcome,
528
+ data.profile_id,
529
+ );
512
530
 
513
- if (!destination) {
514
- 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.');
515
536
  }
516
537
 
517
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.
518
541
  success: true,
519
- 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,
520
549
  };
521
550
  }
522
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
+
523
565
  /**
524
- * Valida um perfil whatsapp-official contra a Graph API (lê o WABA com o token)
525
- * e registra o resultado no config. Nunca devolve o token/secret na resposta.
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.
526
570
  */
527
- private async testWhatsappProfile(
571
+ private async recordValidation(
528
572
  providerSlug: string,
529
573
  slug: string,
530
- effectiveConfig: Record<string, unknown> | null,
531
- ) {
532
- if (providerSlug !== 'whatsapp-official') {
533
- throw new BadRequestException(
534
- `Integration profile test is not available for provider "${providerSlug}".`,
535
- );
536
- }
537
-
538
- const cfg = buildWhatsappOfficialConfigFromIntegration(effectiveConfig);
539
-
540
- if (!cfg.accessToken) {
541
- throw new BadRequestException('WhatsApp access token is required.');
542
- }
543
- if (!cfg.wabaId) {
544
- throw new BadRequestException('WhatsApp Business Account ID is required.');
545
- }
546
- if (!cfg.appSecret) {
547
- throw new BadRequestException(
548
- 'Meta App Secret is required to validate webhook signatures.',
549
- );
550
- }
551
- if (!cfg.verifyToken) {
552
- throw new BadRequestException('Webhook verify token is required.');
553
- }
554
-
555
- const url = `https://graph.facebook.com/${cfg.graphApiVersion}/${encodeURIComponent(
556
- cfg.wabaId,
557
- )}?fields=id,name`;
558
-
559
- let name = '';
560
- let failure: string | null = null;
574
+ outcome: IntegrationTestOutcome,
575
+ profileId?: number,
576
+ ): Promise<boolean> {
561
577
  try {
562
- const response = await fetch(url, {
563
- headers: { Authorization: `Bearer ${cfg.accessToken}` },
578
+ const stored = await this.prismaService.integration_profile.findUnique({
579
+ where: profileId ? { id: profileId } : { slug },
580
+ select: { id: true, config: true },
564
581
  });
565
- const body = (await response.json().catch(() => ({}))) as {
566
- name?: string;
567
- error?: { message?: string };
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,
568
594
  };
569
- if (!response.ok) {
570
- // A mensagem da Meta não contém o token; ainda assim só propagamos o texto dela.
571
- failure =
572
- body?.error?.message ?? `Graph API returned HTTP ${response.status}.`;
573
- } else {
574
- name = String(body?.name ?? '');
575
- }
576
- } catch (error) {
577
- failure = error instanceof Error ? error.message : 'Graph API is unreachable.';
578
- }
579
595
 
580
- await this.recordWhatsappValidation(providerSlug, slug, failure);
581
-
582
- if (failure) {
583
- throw new BadRequestException(`WhatsApp validation failed: ${failure}`);
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;
584
611
  }
585
-
586
- return { success: true, destination: name || cfg.wabaId };
587
- }
588
-
589
- /** Grava metadados (não-secretos) da última validação no config do perfil. */
590
- private async recordWhatsappValidation(
591
- providerSlug: string,
592
- slug: string,
593
- failure: string | null,
594
- ) {
595
- const stored = await this.prismaService.integration_profile.findUnique({
596
- where: { slug },
597
- select: { id: true, config: true },
598
- });
599
- // Perfil ainda não salvo (teste no fluxo de criação): nada a registrar.
600
- if (!stored) return;
601
-
602
- // `stored.config` vem decifrado pelo middleware; recifra-mos ao gravar.
603
- const plain = {
604
- ...((stored.config as Record<string, unknown>) ?? {}),
605
- last_validated_at: new Date().toISOString(),
606
- last_validation_status: failure ? 'error' : 'ok',
607
- last_error: failure ?? null,
608
- };
609
-
610
- await this.prismaService.integration_profile.update({
611
- where: { id: stored.id },
612
- data: {
613
- config: this.credentialCrypto.encryptConfig(providerSlug, plain) as object,
614
- },
615
- });
616
612
  }
617
613
 
618
614
  async exportProfiles({
@@ -325,6 +325,28 @@ describe('integration-profile.utils', () => {
325
325
  });
326
326
  });
327
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
+
328
350
  it('lança para provider desconhecido', () => {
329
351
  expect(() => buildAiConfigFromIntegration('llama', {})).toThrow(
330
352
  BadRequestException,
@@ -300,21 +300,58 @@ export function buildKubernetesConfigFromIntegration(
300
300
 
301
301
  // ─── AI utilities ─────────────────────────────────────────────────────────────
302
302
 
303
- /** 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. */
304
314
  export function buildAiConfigFromIntegration(
305
315
  providerSlug: string,
306
316
  config: unknown,
307
- ): { 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
+ } {
308
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
+
309
330
  switch (providerSlug.toLowerCase()) {
310
331
  case 'openai':
311
332
  return {
312
333
  apiKey: String(cfg.api_key ?? ''),
313
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,
314
347
  };
315
348
  case 'gemini':
316
349
  case 'claude':
317
- return { apiKey: String(cfg.api_key ?? '') };
350
+ return {
351
+ apiKey: String(cfg.api_key ?? ''),
352
+ ...(model ? { model } : {}),
353
+ ...(timeoutMs ? { timeoutMs } : {}),
354
+ };
318
355
  default:
319
356
  throw new BadRequestException(`Unsupported AI provider: ${providerSlug}`);
320
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
+ ];
@@ -0,0 +1,92 @@
1
+ import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
2
+ import { CAPTCHA_TESTERS } from './captcha.testers';
3
+ import { IntegrationTestContext, IntegrationTester } from './integration-tester.types';
4
+
5
+ const bySlug = (slug: string): IntegrationTester =>
6
+ CAPTCHA_TESTERS.find((tester) => tester.providerSlug === slug)!;
7
+
8
+ const ctx = (): IntegrationTestContext => ({
9
+ signal: AbortSignal.timeout(5_000),
10
+ typeSlug: 'captcha',
11
+ providerSlug: 'test',
12
+ secretValues: [],
13
+ });
14
+
15
+ function siteverify(errorCodes: string[], success = false) {
16
+ return {
17
+ ok: true,
18
+ status: 200,
19
+ text: async () => JSON.stringify({ success, 'error-codes': errorCodes }),
20
+ } as unknown as Response;
21
+ }
22
+
23
+ let fetchMock: jest.Mock;
24
+
25
+ beforeEach(() => {
26
+ fetchMock = jest.fn();
27
+ global.fetch = fetchMock as unknown as typeof fetch;
28
+ });
29
+
30
+ afterEach(() => {
31
+ jest.restoreAllMocks();
32
+ });
33
+
34
+ describe.each([
35
+ ['recaptcha', 'Invalid reCAPTCHA secret key.'],
36
+ ['cloudflare-turnstile', 'Invalid Turnstile secret key.'],
37
+ ])('%s tester', (slug, invalidSecretMessage) => {
38
+ const tester = bySlug(slug);
39
+
40
+ it('reprova quando o siteverify recusa o segredo', async () => {
41
+ fetchMock.mockResolvedValue(siteverify(['invalid-input-secret']));
42
+
43
+ const outcome = await tester.test(
44
+ { site_key: 'site', secret_key: 'wrong' },
45
+ ctx(),
46
+ );
47
+
48
+ expect(outcome).toEqual({ ok: false, error: invalidSecretMessage });
49
+ });
50
+
51
+ it('aprova quando o siteverify aceita o segredo e só reclama do token de teste', async () => {
52
+ fetchMock.mockResolvedValue(
53
+ siteverify(['missing-input-response', 'invalid-input-response']),
54
+ );
55
+
56
+ const outcome = await tester.test(
57
+ { site_key: 'site', secret_key: 'right' },
58
+ ctx(),
59
+ );
60
+
61
+ expect(outcome.ok).toBe(true);
62
+ });
63
+
64
+ it('reprova sem ir à rede quando falta o segredo', async () => {
65
+ const outcome = await tester.test({ site_key: 'site' }, ctx());
66
+
67
+ expect(outcome.ok).toBe(false);
68
+ expect(fetchMock).not.toHaveBeenCalled();
69
+ });
70
+ });
71
+
72
+ describe('altcha tester', () => {
73
+ const tester = bySlug('altcha');
74
+
75
+ it('valida a chave localmente e avisa que não há verificação remota', async () => {
76
+ const outcome = await tester.test(
77
+ { hmac_key: 'uma-chave-hmac-suficientemente-longa' },
78
+ ctx(),
79
+ );
80
+
81
+ expect(outcome.ok).toBe(true);
82
+ expect(outcome.warning).toContain('self-hosted');
83
+ expect(fetchMock).not.toHaveBeenCalled();
84
+ });
85
+
86
+ it('reprova uma chave curta demais', async () => {
87
+ const outcome = await tester.test({ hmac_key: 'curta' }, ctx());
88
+
89
+ expect(outcome.ok).toBe(false);
90
+ expect(outcome.error).toContain('too short');
91
+ });
92
+ });