@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
@@ -0,0 +1,18 @@
1
+ columns:
2
+ - type: pk
3
+ # SHA-1 da senha em claro, 20 bytes. SHA-1 porque e o formato em que os corpus
4
+ # publicos de vazamento (Pwned Passwords) sao distribuidos — aqui ele e
5
+ # identificador de item de lista publica, nao protecao de senha. As senhas do
6
+ # sistema continuam em hash de senha proprio e as do cofre em Argon2id+AES-GCM.
7
+ - name: hash
8
+ type: bytes
9
+ isUnique: true
10
+ # Quantas vezes o hash apareceu nos vazamentos conhecidos, quando o dump
11
+ # informa. 0 = desconhecido (caso do seed base, que vem de lista curada).
12
+ - name: occurrences
13
+ type: int
14
+ default: 0
15
+ - type: created_at
16
+
17
+ indices:
18
+ - columns: [occurrences]
@@ -0,0 +1,35 @@
1
+ columns:
2
+ - type: pk
3
+ - type: slug
4
+ - name: is_default
5
+ type: boolean
6
+ default: false
7
+ comment: "Layout applied to every mail that does not skip or override it"
8
+ - name: wrapper
9
+ type: text
10
+ comment: "Full HTML document with {{{header}}} / {{{content}}} / {{{footer}}} tokens. Structural (CSS) and therefore not translatable."
11
+ - name: name
12
+ type: locale_varchar
13
+ length: 255
14
+ locale:
15
+ en: Name
16
+ pt: Nome
17
+ - name: header
18
+ type: locale_text
19
+ isNullable: true
20
+ locale:
21
+ en: Header
22
+ pt: Cabeçalho
23
+ - name: footer
24
+ type: locale_text
25
+ isNullable: true
26
+ locale:
27
+ en: Footer
28
+ pt: Rodapé
29
+ - type: created_at
30
+ - type: updated_at
31
+
32
+ indices:
33
+ - columns: [is_default]
34
+ isUnique: true
35
+ where: is_default = true
@@ -10,3 +10,7 @@ columns:
10
10
  - name: name
11
11
  - type: created_at
12
12
  - type: updated_at
13
+
14
+ indices:
15
+ - columns: [mail_id, name]
16
+ isUnique: true
@@ -33,6 +33,7 @@ columns:
33
33
  - switch
34
34
  - checkbox
35
35
  - entity-picker
36
+ - link
36
37
  default: input-text
37
38
  - name: value
38
39
  length: 1023
@@ -0,0 +1,59 @@
1
+ columns:
2
+ - type: pk
3
+ # Origem no formato "<modulo>.<area>", ex.: core.mail, legacy.reconcile.
4
+ - name: source
5
+ type: varchar
6
+ length: 120
7
+ # Identificador estavel da falha, ex.: mail_send_failed.
8
+ - name: code
9
+ type: varchar
10
+ length: 120
11
+ - name: severity
12
+ type: enum
13
+ values:
14
+ - warning
15
+ - error
16
+ - critical
17
+ default: error
18
+ - name: message
19
+ type: text
20
+ - name: context
21
+ type: json
22
+ isNullable: true
23
+ # Hash de (source, code, chave de agrupamento). E o que impede uma falha
24
+ # repetitiva de virar milhares de linhas: repeticao vira contador.
25
+ - name: fingerprint
26
+ type: varchar
27
+ length: 64
28
+ isUnique: true
29
+ - name: occurrences
30
+ type: int
31
+ default: 1
32
+ - name: first_seen_at
33
+ type: datetime
34
+ - name: last_seen_at
35
+ type: datetime
36
+ # Ultima vez que este incidente gerou aviso; base do cooldown.
37
+ - name: notified_at
38
+ type: datetime
39
+ isNullable: true
40
+ - name: resolved_at
41
+ type: datetime
42
+ isNullable: true
43
+ - name: resolved_by
44
+ type: fk
45
+ isNullable: true
46
+ references:
47
+ table: user
48
+ column: id
49
+ onDelete: SET NULL
50
+ onUpdate: CASCADE
51
+ - type: created_at
52
+ - type: updated_at
53
+
54
+ indices:
55
+ - columns: [source]
56
+ - columns: [code]
57
+ - columns: [severity]
58
+ - columns: [resolved_at]
59
+ - columns: [last_seen_at]
@@ -0,0 +1,36 @@
1
+ # Unified presence per user: app heartbeat (real-time, this application) merged
2
+ # with Microsoft Teams presence (when the Teams integration is configured). One
3
+ # row per user, upserted by the heartbeat endpoint and by the Microsoft presence
4
+ # processor.
5
+ columns:
6
+ - type: pk
7
+ - name: user_id
8
+ type: fk
9
+ references:
10
+ table: user
11
+ column: id
12
+ onDelete: CASCADE
13
+ onUpdate: CASCADE
14
+ # Last time the user's browser pinged the heartbeat endpoint (app presence).
15
+ - name: last_heartbeat_at
16
+ type: timestamptz
17
+ isNullable: true
18
+ # Latest Microsoft Teams presence (Available/Busy/Away/DoNotDisturb/Offline/...).
19
+ - name: teams_availability
20
+ type: varchar
21
+ length: 64
22
+ isNullable: true
23
+ - name: teams_activity
24
+ type: varchar
25
+ length: 64
26
+ isNullable: true
27
+ - name: teams_updated_at
28
+ type: timestamptz
29
+ isNullable: true
30
+ - type: created_at
31
+ - type: updated_at
32
+
33
+ indices:
34
+ - columns: [user_id]
35
+ isUnique: true
36
+ - columns: [last_heartbeat_at]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/core",
3
- "version": "0.0.387",
3
+ "version": "0.0.390",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,8 +20,10 @@
20
20
  "@nestjs/event-emitter": "*",
21
21
  "@nestjs/jwt": "^11",
22
22
  "@nestjs/mapped-types": "*",
23
+ "@nestjs/platform-socket.io": "^11",
23
24
  "@nestjs/schedule": "^6.0.1",
24
25
  "@nestjs/throttler": "^6.4.0",
26
+ "@nestjs/websockets": "^11",
25
27
  "@simplewebauthn/server": "^13.2.2",
26
28
  "argon2": "^0.44.0",
27
29
  "axios": "^1.9.0",
@@ -37,16 +39,18 @@
37
39
  "qrcode": "^1.5.4",
38
40
  "redis": "4.7.1",
39
41
  "rxjs": "^7.8.2",
42
+ "socket.io": "^4.8.1",
40
43
  "sharp": "^0.34.2",
41
44
  "speakeasy": "^2.0.0",
42
45
  "ua-parser-js": "^2.0.10",
43
46
  "uuid": "^11.1.0",
44
47
  "@hed-hog/api-prisma": "0.0.6",
48
+ "@hed-hog/api-locale": "0.0.14",
49
+ "@hed-hog/vault-crypto": "0.0.1",
50
+ "@hed-hog/api": "0.0.8",
45
51
  "@hed-hog/api-types": "0.0.1",
46
52
  "@hed-hog/api-mail": "0.0.9",
47
- "@hed-hog/api-pagination": "0.0.7",
48
- "@hed-hog/api-locale": "0.0.14",
49
- "@hed-hog/api": "0.0.8"
53
+ "@hed-hog/api-pagination": "0.0.7"
50
54
  },
51
55
  "exports": {
52
56
  ".": {
@@ -26,8 +26,10 @@ export class AccessLogInterceptor implements NestInterceptor {
26
26
  return next.handle().pipe(
27
27
  tap(() => {
28
28
  const userId: number | undefined = request.auth?.sub;
29
- const forwarded = request.headers['x-forwarded-for'] as string | undefined;
30
- const ip: string = forwarded ? forwarded.split(',')[0].trim() : (request.ip ?? '');
29
+ // request.ip já resolve o IP real do cliente respeitando `trust proxy` (main.ts):
30
+ // ler x-forwarded-for na mão aqui pegava o primeiro valor da lista, que é
31
+ // exatamente o mais fácil de forjar pelo próprio cliente.
32
+ const ip: string = request.ip ?? '';
31
33
  const userAgent: string = (request.headers['user-agent'] as string) ?? '';
32
34
  const method: string = request.method ?? '';
33
35
 
@@ -0,0 +1,319 @@
1
+ import axios from 'axios';
2
+ import {
3
+ attachedFileBlock,
4
+ binaryAttachmentMarker,
5
+ unreadablePdfMarker,
6
+ } from './ai-attachment.fragments';
7
+ import { AiService } from './ai.service';
8
+
9
+ jest.mock('axios');
10
+
11
+ const mockedAxios = axios as jest.Mocked<typeof axios>;
12
+
13
+ /**
14
+ * Fidelidade byte a byte da extração.
15
+ *
16
+ * As funções `legacy*` abaixo são cópias literais do que `chatWithGemini` e
17
+ * `buildOpenAiUserContent` montavam inline antes dos marcadores virarem helpers
18
+ * — `[Attached file: …]` estava triplicado, `[Binary attachment: …]` e
19
+ * `[PDF attachment with unreadable text: …]` moram no mesmo bloco. Um `\n`
20
+ * perdido ou um espaço a mais em torno dos `|` muda o que o modelo recebe SEM
21
+ * levantar erro algum. Este é o único check que pega isso — não "arrume" estas
22
+ * cópias.
23
+ *
24
+ * Repare no ponto delicado: no legado do OpenAI o `\n\n` ficava no template do
25
+ * `return`, e agora vem de dentro de `attachedFileBlock`. Os bytes finais são os
26
+ * mesmos, e é exatamente isso que `legacyOpenAiReturn` prova.
27
+ */
28
+
29
+ type LegacyAttachment = { filename: string; mimeType: string; buffer: Buffer };
30
+
31
+ function legacyGeminiTextPart(attachment: LegacyAttachment, utf8Text: string): string {
32
+ return `\n\n[Attached file: ${attachment.filename}]\n${utf8Text}`;
33
+ }
34
+
35
+ function legacyGeminiPdfPart(attachment: LegacyAttachment, pdfText: string): string {
36
+ return `\n\n[Attached file: ${attachment.filename}]\n${pdfText}`;
37
+ }
38
+
39
+ function legacyUnreadablePdf(attachment: LegacyAttachment): string {
40
+ return `[PDF attachment with unreadable text: ${attachment.filename}]`;
41
+ }
42
+
43
+ function legacyBinaryMarker(attachment: LegacyAttachment): string {
44
+ return `[Binary attachment: ${attachment.filename} | ${attachment.mimeType} | ${attachment.buffer.length} bytes]`;
45
+ }
46
+
47
+ function legacyOpenAiReturn(
48
+ message: string,
49
+ attachment: LegacyAttachment,
50
+ text: string,
51
+ ): string {
52
+ return `${message}\n\n[Attached file: ${attachment.filename}]\n${text}`;
53
+ }
54
+
55
+ function makeAttachment(
56
+ filename: string,
57
+ mimeType: string,
58
+ content: string,
59
+ ): LegacyAttachment {
60
+ return { filename, mimeType, buffer: Buffer.from(content, 'utf8') };
61
+ }
62
+
63
+ const TEXT_ATTACHMENT = makeAttachment('notas.txt', 'text/plain', 'linha 1\nlinha 2');
64
+ const PDF_ATTACHMENT = makeAttachment('contrato.pdf', 'application/pdf', '%PDF-1.4');
65
+ const BINARY_ATTACHMENT = makeAttachment('planilha.xlsx', 'application/octet-stream', 'PK');
66
+
67
+ describe('marcadores de anexo — fidelidade', () => {
68
+ it('bloco de arquivo de texto é idêntico ao original do Gemini', () => {
69
+ const utf8Text = TEXT_ATTACHMENT.buffer.toString('utf8');
70
+
71
+ expect(attachedFileBlock(TEXT_ATTACHMENT.filename, utf8Text)).toBe(
72
+ legacyGeminiTextPart(TEXT_ATTACHMENT, utf8Text),
73
+ );
74
+ });
75
+
76
+ it('bloco de PDF extraído é idêntico ao original do Gemini', () => {
77
+ const pdfText = 'Cláusula 1ª — objeto do contrato.';
78
+
79
+ expect(attachedFileBlock(PDF_ATTACHMENT.filename, pdfText)).toBe(
80
+ legacyGeminiPdfPart(PDF_ATTACHMENT, pdfText),
81
+ );
82
+ });
83
+
84
+ it('bloco do OpenAI é idêntico ao original mesmo com o \\n\\n vindo do helper', () => {
85
+ const message = 'Resuma o anexo.';
86
+ const text = TEXT_ATTACHMENT.buffer.toString('utf8');
87
+
88
+ expect(`${message}${attachedFileBlock(TEXT_ATTACHMENT.filename, text)}`).toBe(
89
+ legacyOpenAiReturn(message, TEXT_ATTACHMENT, text),
90
+ );
91
+ });
92
+
93
+ it('marcador de binário é idêntico ao original, com os pipes espaçados', () => {
94
+ expect(
95
+ binaryAttachmentMarker(
96
+ BINARY_ATTACHMENT.filename,
97
+ BINARY_ATTACHMENT.mimeType,
98
+ BINARY_ATTACHMENT.buffer.length,
99
+ ),
100
+ ).toBe(legacyBinaryMarker(BINARY_ATTACHMENT));
101
+
102
+ expect(binaryAttachmentMarker('a.bin', 'application/octet-stream', 12)).toBe(
103
+ '[Binary attachment: a.bin | application/octet-stream | 12 bytes]',
104
+ );
105
+ });
106
+
107
+ it('marcador de PDF ilegível é idêntico ao original', () => {
108
+ expect(unreadablePdfMarker(PDF_ATTACHMENT.filename)).toBe(
109
+ legacyUnreadablePdf(PDF_ATTACHMENT),
110
+ );
111
+ });
112
+
113
+ it('preserva nome de arquivo com espaço, acento e pipe', () => {
114
+ const weird = makeAttachment('nota fiscal | 2ª via.pdf', 'application/pdf', 'x');
115
+
116
+ expect(attachedFileBlock(weird.filename, 'corpo')).toBe(
117
+ legacyGeminiPdfPart(weird, 'corpo'),
118
+ );
119
+ expect(binaryAttachmentMarker(weird.filename, weird.mimeType, weird.buffer.length)).toBe(
120
+ legacyBinaryMarker(weird),
121
+ );
122
+ expect(unreadablePdfMarker(weird.filename)).toBe(legacyUnreadablePdf(weird));
123
+ });
124
+
125
+ it('corpo vazio mantém a quebra final, e zero bytes continua "0 bytes"', () => {
126
+ const empty = makeAttachment('vazio.txt', 'text/plain', '');
127
+
128
+ expect(attachedFileBlock(empty.filename, '')).toBe(legacyGeminiTextPart(empty, ''));
129
+ expect(attachedFileBlock(empty.filename, '')).toBe('\n\n[Attached file: vazio.txt]\n');
130
+ expect(binaryAttachmentMarker(empty.filename, empty.mimeType, empty.buffer.length)).toBe(
131
+ legacyBinaryMarker(empty),
132
+ );
133
+ });
134
+ });
135
+
136
+ /**
137
+ * O que sai no fio. Este bloco é o que pega "troquei o call site pelo helper
138
+ * errado" — os asserts comparam o corpo da requisição com as cópias legadas.
139
+ */
140
+ describe('AiService — anexos no fio', () => {
141
+ let service: AiService;
142
+
143
+ const aiProfile = { apiKey: 'sk-test', model: undefined, timeoutMs: undefined };
144
+
145
+ beforeEach(() => {
146
+ const prisma = {} as any;
147
+ const settingService = { getSettingValues: jest.fn().mockResolvedValue({}) } as any;
148
+ const fileService = {} as any;
149
+ const aiExecution = {
150
+ start: jest.fn().mockResolvedValue(1),
151
+ recordStep: jest.fn().mockResolvedValue(undefined),
152
+ finish: jest.fn().mockResolvedValue(undefined),
153
+ } as any;
154
+ const promptResolver = { resolveMany: jest.fn() };
155
+
156
+ service = new AiService(prisma, settingService, fileService, aiExecution, promptResolver as any);
157
+
158
+ jest.spyOn(service as any, 'getAiProfile').mockResolvedValue(aiProfile);
159
+ jest.spyOn(service as any, 'getDefaultProvider').mockResolvedValue('openai');
160
+
161
+ mockedAxios.post.mockResolvedValue({
162
+ data: {
163
+ choices: [{ message: { content: 'ok' } }],
164
+ candidates: [{ content: { parts: [{ text: 'ok' }] } }],
165
+ },
166
+ } as any);
167
+ });
168
+
169
+ afterEach(() => {
170
+ jest.restoreAllMocks();
171
+ mockedAxios.post.mockReset();
172
+ });
173
+
174
+ function useAttachment(attachment: LegacyAttachment | null) {
175
+ jest.spyOn(service as any, 'resolveAttachment').mockResolvedValue(attachment);
176
+ }
177
+
178
+ function lastBody(): Record<string, any> {
179
+ return mockedAxios.post.mock.calls.at(-1)?.[1] as Record<string, any>;
180
+ }
181
+
182
+ describe('Gemini', () => {
183
+ it('embrulha anexo de texto exatamente como o código original', async () => {
184
+ useAttachment(TEXT_ATTACHMENT);
185
+
186
+ await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
187
+
188
+ expect(lastBody().contents[0].parts[1].text).toBe(
189
+ legacyGeminiTextPart(TEXT_ATTACHMENT, TEXT_ATTACHMENT.buffer.toString('utf8')),
190
+ );
191
+ });
192
+
193
+ it('embrulha PDF com texto extraído exatamente como o código original', async () => {
194
+ const pdfText = 'Cláusula 1ª — objeto do contrato.';
195
+ useAttachment(PDF_ATTACHMENT);
196
+ jest.spyOn(service as any, 'extractPdfText').mockResolvedValue(pdfText);
197
+
198
+ await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
199
+
200
+ expect(lastBody().contents[0].parts[1].text).toBe(
201
+ legacyGeminiPdfPart(PDF_ATTACHMENT, pdfText),
202
+ );
203
+ });
204
+
205
+ it('PDF ilegível continua indo como inline_data, sem marcador de texto', async () => {
206
+ useAttachment(PDF_ATTACHMENT);
207
+ jest.spyOn(service as any, 'extractPdfText').mockResolvedValue('');
208
+
209
+ await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
210
+
211
+ const part = lastBody().contents[0].parts[1];
212
+ expect(part).not.toHaveProperty('text');
213
+ expect(part.inline_data.mime_type).toBe('application/pdf');
214
+ });
215
+
216
+ it('binário continua indo como inline_data, sem marcador de texto', async () => {
217
+ useAttachment(BINARY_ATTACHMENT);
218
+
219
+ await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
220
+
221
+ const part = lastBody().contents[0].parts[1];
222
+ expect(part).not.toHaveProperty('text');
223
+ expect(part.inline_data.mime_type).toBe('application/octet-stream');
224
+ });
225
+
226
+ it('sem anexo, a mensagem vai crua num único part', async () => {
227
+ useAttachment(null);
228
+
229
+ await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
230
+
231
+ expect(lastBody().contents[0].parts).toHaveLength(1);
232
+ expect(lastBody().contents[0].parts[0].text).toBe('Resuma.');
233
+ });
234
+ });
235
+
236
+ describe('OpenAI', () => {
237
+ it('embrulha anexo de texto exatamente como o código original', async () => {
238
+ useAttachment(TEXT_ATTACHMENT);
239
+
240
+ await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
241
+
242
+ expect(lastBody().messages[0].content).toBe(
243
+ legacyOpenAiReturn(
244
+ 'Resuma.',
245
+ TEXT_ATTACHMENT,
246
+ TEXT_ATTACHMENT.buffer.toString('utf8'),
247
+ ),
248
+ );
249
+ });
250
+
251
+ it('embrulha PDF com texto extraído exatamente como o código original', async () => {
252
+ const pdfText = 'Cláusula 1ª — objeto do contrato.';
253
+ useAttachment(PDF_ATTACHMENT);
254
+ jest.spyOn(service as any, 'extractPdfText').mockResolvedValue(pdfText);
255
+
256
+ await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
257
+
258
+ expect(lastBody().messages[0].content).toBe(
259
+ legacyOpenAiReturn('Resuma.', PDF_ATTACHMENT, pdfText),
260
+ );
261
+ });
262
+
263
+ it('PDF ilegível cai no marcador de PDF, dentro do bloco de arquivo', async () => {
264
+ useAttachment(PDF_ATTACHMENT);
265
+ jest.spyOn(service as any, 'extractPdfText').mockResolvedValue('');
266
+
267
+ await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
268
+
269
+ expect(lastBody().messages[0].content).toBe(
270
+ legacyOpenAiReturn('Resuma.', PDF_ATTACHMENT, legacyUnreadablePdf(PDF_ATTACHMENT)),
271
+ );
272
+ });
273
+
274
+ it('binário cai no marcador de binário, dentro do bloco de arquivo', async () => {
275
+ useAttachment(BINARY_ATTACHMENT);
276
+
277
+ await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
278
+
279
+ expect(lastBody().messages[0].content).toBe(
280
+ legacyOpenAiReturn(
281
+ 'Resuma.',
282
+ BINARY_ATTACHMENT,
283
+ legacyBinaryMarker(BINARY_ATTACHMENT),
284
+ ),
285
+ );
286
+ });
287
+
288
+ it('imagem continua indo por image_url, sem nenhum marcador', async () => {
289
+ const image = makeAttachment('foto.png', 'image/png', 'binario');
290
+ useAttachment(image);
291
+
292
+ await service.chat({ message: 'Descreva.', provider: 'openai' } as any);
293
+
294
+ const content = lastBody().messages[0].content;
295
+ expect(content[0]).toEqual({ type: 'text', text: 'Descreva.' });
296
+ expect(content[1].type).toBe('image_url');
297
+ expect(JSON.stringify(content)).not.toContain('[Attached file:');
298
+ });
299
+
300
+ it('no DeepSeek, imagem cai no marcador de binário (o modelo não tem visão)', async () => {
301
+ const image = makeAttachment('foto.png', 'image/png', 'binario');
302
+ useAttachment(image);
303
+
304
+ await service.chat({ message: 'Descreva.', provider: 'deepseek' } as any);
305
+
306
+ expect(lastBody().messages[0].content).toBe(
307
+ legacyOpenAiReturn('Descreva.', image, legacyBinaryMarker(image)),
308
+ );
309
+ });
310
+
311
+ it('sem anexo, a mensagem vai crua — sem \\n\\n pendurado', async () => {
312
+ useAttachment(null);
313
+
314
+ await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
315
+
316
+ expect(lastBody().messages[0].content).toBe('Resuma.');
317
+ });
318
+ });
319
+ });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Framing mecânico de anexo enviado ao modelo — deliberadamente FORA do registry
3
+ * de `ai_instruction` (ver o docblock de `ai.prompts.ts`).
4
+ *
5
+ * Estes marcadores andam em lockstep com `isTextMime`/`isPdfMime`/`extractPdfText`
6
+ * em `ai.service.ts`: são o que diz ao modelo que o texto a seguir é o conteúdo de
7
+ * um arquivo, e não a mensagem do usuário. Antes estavam copiados literalmente nos
8
+ * dois caminhos de provider (Gemini e OpenAI), onde uma cópia podia ser corrigida
9
+ * e a outra esquecida sem gerar erro nenhum.
10
+ *
11
+ * O `\n\n` inicial faz parte do bloco: no Gemini ele abre um `part` separado, no
12
+ * OpenAI ele é a junta logo depois de `${message}`. Nos dois casos os bytes finais
13
+ * são exatamente os mesmos.
14
+ *
15
+ * Coberto byte a byte por `ai-attachment.fragments.spec.ts` — não "arrume" o texto.
16
+ */
17
+
18
+ /** Bloco que embrulha o conteúdo textual extraído de um anexo. */
19
+ export function attachedFileBlock(filename: string, body: string): string {
20
+ return `\n\n[Attached file: ${filename}]\n${body}`;
21
+ }
22
+
23
+ /** Usado quando o anexo não é texto nem PDF legível e vai apenas descrito. */
24
+ export function binaryAttachmentMarker(
25
+ filename: string,
26
+ mimeType: string,
27
+ bytes: number,
28
+ ): string {
29
+ return `[Binary attachment: ${filename} | ${mimeType} | ${bytes} bytes]`;
30
+ }
31
+
32
+ /** Usado quando `extractPdfText` não consegue extrair nada do PDF. */
33
+ export function unreadablePdfMarker(filename: string): string {
34
+ return `[PDF attachment with unreadable text: ${filename}]`;
35
+ }
@@ -0,0 +1,38 @@
1
+ import { registerAiPrompts } from '../ai-instruction/ai-prompt-registry';
2
+
3
+ /**
4
+ * Core AI prompts.
5
+ *
6
+ * Deliberately NOT moved here: the attachment wrappers (`[Attached file: …]`,
7
+ * `[Binary attachment: …]`, `[PDF attachment with unreadable text: …]`). Those are
8
+ * mechanical framing that must stay in lockstep with `isTextMime`/`isPdfMime`/
9
+ * `buildOpenAiUserContent` on the parsing side — editable prose they are not.
10
+ * They now live in `ai-attachment.fragments.ts` (single copy, in code), covered
11
+ * byte for byte by `ai-attachment.fragments.spec.ts`.
12
+ */
13
+
14
+ export const CORE_AI_PROMPT_SLUGS = {
15
+ agentDefaultInstructions: 'task.core.ai-agent.default-instructions.system',
16
+ } as const;
17
+
18
+ /** Used when an agent is created without explicit instructions. */
19
+ export const AGENT_DEFAULT_INSTRUCTIONS_PROMPT =
20
+ 'You are the assistant identified by slug {{slug}}.';
21
+
22
+ registerAiPrompts([
23
+ {
24
+ slug: CORE_AI_PROMPT_SLUGS.agentDefaultInstructions,
25
+ name: 'AI agent — instruções padrão',
26
+ moduleSlug: 'core',
27
+ locale: 'en',
28
+ fallback: AGENT_DEFAULT_INSTRUCTIONS_PROMPT,
29
+ variables: {
30
+ slug: {
31
+ type: 'string',
32
+ required: true,
33
+ description: 'Slug do agente sendo criado.',
34
+ sample: 'finance-payable-extractor',
35
+ },
36
+ },
37
+ },
38
+ ]);