@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
@@ -13,11 +13,37 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
13
13
  };
14
14
  var AiInstructionService_1;
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.AiInstructionService = void 0;
16
+ exports.AiInstructionService = exports.FALLBACK_SYSTEM_PROMPT = void 0;
17
17
  const api_prisma_1 = require("@hed-hog/api-prisma");
18
18
  const common_1 = require("@nestjs/common");
19
+ const node_crypto_1 = require("node:crypto");
20
+ const redis_pubsub_1 = require("../redis/redis-pubsub");
21
+ const ai_prompt_registry_1 = require("./ai-prompt-registry");
22
+ const ai_prompt_template_util_1 = require("./ai-prompt-template.util");
23
+ /**
24
+ * Cross-pod invalidation happens through Redis, with the database version check
25
+ * as backup. These TTLs are the last resort for when both are unavailable.
26
+ */
19
27
  const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
20
- const FALLBACK_SYSTEM_PROMPT = 'You are a helpful assistant with access to tools from the HedHog system. ' +
28
+ const TASK_CACHE_TTL_MS = 60 * 1000;
29
+ const NEGATIVE_CACHE_TTL_MS = 60 * 1000;
30
+ /**
31
+ * Reuses the generic runtime-version table owned by the settings service. No
32
+ * column there is setting-specific, and the unique index on `scope` means a new
33
+ * scope needs no migration — the idempotent INSERT below creates its own row.
34
+ */
35
+ const RUNTIME_STATE_SCOPE = 'ai_instruction';
36
+ /**
37
+ * Columns are cast explicitly because `$queryRaw` returns DECIMAL as
38
+ * `Prisma.Decimal`, which serializes as a string over HTTP and becomes NaN in
39
+ * arithmetic. Keep every SELECT in this file using this list.
40
+ */
41
+ const INSTRUCTION_COLUMNS = api_prisma_1.Prisma.sql `
42
+ id, slug, layer, name, content, variables_schema, locale, module_slug,
43
+ is_active, version, model, temperature::float8 AS temperature, max_tokens,
44
+ is_locked, created_at, updated_at
45
+ `;
46
+ exports.FALLBACK_SYSTEM_PROMPT = 'You are a helpful assistant with access to tools from the HedHog system. ' +
21
47
  "Use the available tools to answer the user's questions accurately. " +
22
48
  'Always respond in the same language the user writes in.';
23
49
  let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
@@ -25,78 +51,349 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
25
51
  this.prisma = prisma;
26
52
  this.logger = new common_1.Logger(AiInstructionService_1.name);
27
53
  this.cache = new Map();
54
+ this.instanceId = (0, node_crypto_1.randomUUID)();
55
+ this.redisChannel = 'core:ai-instruction:invalidated';
56
+ this.versionCheckIntervalMs = Math.max(1000, Number(process.env.AI_INSTRUCTION_VERSION_CHECK_INTERVAL_MS || 5000));
57
+ this.localCacheVersion = 0;
58
+ this.lastVersionCheckAt = 0;
59
+ this.versionCheckInFlight = null;
60
+ this.versionStateEnsured = false;
61
+ this.lastVersionCheckErrorLogAt = 0;
62
+ this.pubsub = null;
28
63
  }
29
64
  async onModuleInit() {
30
65
  // Warm up global and product layers on startup
31
66
  try {
67
+ // Before the warm-up: starting at version 0 would make the first read
68
+ // think it is behind and throw the freshly warmed cache away.
69
+ await this.syncCacheVersionFromDatabase();
32
70
  await this.getLayer('system');
33
71
  await this.getLayer('product');
72
+ await this.warnAboutUnseededPrompts();
34
73
  }
35
74
  catch (_a) {
36
- // DB may not be ready yet; cache will fill on first request
75
+ // DB may not be ready yet; cache and version fill in on first request
76
+ }
77
+ // Outside the try: createRedisPubSub already handles its own failures.
78
+ this.pubsub = await (0, redis_pubsub_1.createRedisPubSub)({
79
+ channel: this.redisChannel,
80
+ logger: this.logger,
81
+ label: 'ai instruction',
82
+ onMessage: (raw) => this.handleInvalidationMessage(raw),
83
+ });
84
+ }
85
+ async onModuleDestroy() {
86
+ var _a;
87
+ await ((_a = this.pubsub) === null || _a === void 0 ? void 0 : _a.close());
88
+ }
89
+ /**
90
+ * Reports prompts declared in code that have no row yet. Without this, a
91
+ * forgotten seed only surfaces the first time that AI flow runs — which for
92
+ * essay grading means the first graded exam.
93
+ */
94
+ async warnAboutUnseededPrompts() {
95
+ const definitions = (0, ai_prompt_registry_1.listAiPromptDefinitions)();
96
+ if (!definitions.length)
97
+ return;
98
+ const records = await this.getRecordsBySlugs(definitions.map((d) => d.slug));
99
+ const missing = definitions.filter((d) => !records.get(d.slug)).map((d) => d.slug);
100
+ if (missing.length) {
101
+ this.logger.warn(`${missing.length} AI prompt(s) declared in code have no ai_instruction row ` +
102
+ `and will use the code fallback: ${missing.join(', ')}`);
37
103
  }
38
104
  }
39
105
  // ── Public layer accessors (cached) ──────────────────────────────────────
40
106
  async getLayer(layer, moduleSlug) {
107
+ var _a;
41
108
  const cacheKey = moduleSlug ? `${layer}:${moduleSlug}` : layer;
42
- const cached = this.cache.get(cacheKey);
43
- if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
44
- return cached.content;
109
+ await this.ensureCacheVersionFresh();
110
+ const cached = this.readCache(cacheKey);
111
+ if (cached !== undefined) {
112
+ return (_a = cached === null || cached === void 0 ? void 0 : cached.content) !== null && _a !== void 0 ? _a : (layer === 'system' ? exports.FALLBACK_SYSTEM_PROMPT : '');
45
113
  }
46
114
  const instruction = await this.findActiveByLayer(layer, moduleSlug);
115
+ this.writeCache(cacheKey, instruction);
47
116
  if (!instruction) {
48
- if (layer === 'system') {
49
- return FALLBACK_SYSTEM_PROMPT;
50
- }
51
- return '';
117
+ return layer === 'system' ? exports.FALLBACK_SYSTEM_PROMPT : '';
52
118
  }
53
- this.cache.set(cacheKey, { content: instruction.content, fetchedAt: Date.now() });
54
119
  return instruction.content;
55
120
  }
56
121
  async getAgentInstruction(agentSlug) {
122
+ var _a, _b;
57
123
  const cacheKey = `agent:${agentSlug}`;
58
- const cached = this.cache.get(cacheKey);
59
- if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
60
- return cached.content;
61
- }
124
+ await this.ensureCacheVersionFresh();
125
+ const cached = this.readCache(cacheKey);
126
+ if (cached !== undefined)
127
+ return (_a = cached === null || cached === void 0 ? void 0 : cached.content) !== null && _a !== void 0 ? _a : '';
62
128
  const instruction = await this.findActiveBySlug(`agent.${agentSlug}`);
63
- if (!instruction)
64
- return '';
65
- this.cache.set(cacheKey, { content: instruction.content, fetchedAt: Date.now() });
66
- return instruction.content;
129
+ this.writeCache(cacheKey, instruction);
130
+ return (_b = instruction === null || instruction === void 0 ? void 0 : instruction.content) !== null && _b !== void 0 ? _b : '';
67
131
  }
68
- invalidateCache(slug) {
69
- if (slug) {
70
- // Cache keys use format "layer" or "layer:identifier"
71
- // Slugs use format "layer.identifier" (e.g., "module.lms", "agent.admin-support")
72
- const dotIndex = slug.indexOf('.');
73
- if (dotIndex === -1) {
74
- this.cache.delete(slug);
132
+ /**
133
+ * Full record by exact slug, cached. This is what `AiPromptResolverService`
134
+ * uses for task prompts — it needs the model params and `is_locked`, not just
135
+ * the content.
136
+ */
137
+ async getRecordBySlug(slug) {
138
+ const cacheKey = `slug:${slug}`;
139
+ await this.ensureCacheVersionFresh();
140
+ const cached = this.readCache(cacheKey);
141
+ if (cached !== undefined)
142
+ return cached;
143
+ const record = await this.findBySlug(slug);
144
+ this.writeCache(cacheKey, record);
145
+ return record;
146
+ }
147
+ /** One query for pipelines that resolve several prompts per call. */
148
+ async getRecordsBySlugs(slugs) {
149
+ const result = new Map();
150
+ const missing = [];
151
+ await this.ensureCacheVersionFresh();
152
+ for (const slug of slugs) {
153
+ const cached = this.readCache(`slug:${slug}`);
154
+ if (cached !== undefined) {
155
+ result.set(slug, cached);
75
156
  }
76
157
  else {
77
- const layer = slug.slice(0, dotIndex);
78
- const identifier = slug.slice(dotIndex + 1);
79
- this.cache.delete(layer);
80
- this.cache.delete(`${layer}:${identifier}`);
158
+ missing.push(slug);
81
159
  }
82
160
  }
83
- else {
161
+ if (missing.length) {
162
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
163
+ SELECT ${INSTRUCTION_COLUMNS}
164
+ FROM ai_instruction WHERE slug IN (${api_prisma_1.Prisma.join(missing)})
165
+ `);
166
+ const found = new Map(rows.map((row) => [row.slug, row]));
167
+ for (const slug of missing) {
168
+ const record = found.get(slug) || null;
169
+ this.writeCache(`slug:${slug}`, record);
170
+ result.set(slug, record);
171
+ }
172
+ }
173
+ return result;
174
+ }
175
+ invalidateCache(slug) {
176
+ if (!slug) {
84
177
  this.cache.clear();
178
+ return;
179
+ }
180
+ // Exact-slug key used by getRecordBySlug/getRecordsBySlugs.
181
+ this.cache.delete(`slug:${slug}`);
182
+ // Layer keys use format "layer" or "layer:identifier", while slugs use
183
+ // "layer.identifier" (e.g. "module.lms", "agent.admin-support").
184
+ const dotIndex = slug.indexOf('.');
185
+ if (dotIndex === -1) {
186
+ this.cache.delete(slug);
187
+ }
188
+ else {
189
+ const layer = slug.slice(0, dotIndex);
190
+ const identifier = slug.slice(dotIndex + 1);
191
+ this.cache.delete(layer);
192
+ this.cache.delete(`${layer}:${identifier}`);
193
+ }
194
+ }
195
+ /** `undefined` = cache miss/expired. `null` = cached absence. */
196
+ readCache(cacheKey) {
197
+ const cached = this.cache.get(cacheKey);
198
+ if (!cached)
199
+ return undefined;
200
+ if (Date.now() - cached.fetchedAt >= cached.ttl) {
201
+ this.cache.delete(cacheKey);
202
+ return undefined;
203
+ }
204
+ return cached.record;
205
+ }
206
+ writeCache(cacheKey, record) {
207
+ const ttl = !record
208
+ ? NEGATIVE_CACHE_TTL_MS
209
+ : record.layer === 'task'
210
+ ? TASK_CACHE_TTL_MS
211
+ : CACHE_TTL_MS;
212
+ this.cache.set(cacheKey, { record, fetchedAt: Date.now(), ttl });
213
+ }
214
+ // ── Cross-pod invalidation ───────────────────────────────────────────────
215
+ handleInvalidationMessage(raw) {
216
+ let payload;
217
+ try {
218
+ payload = JSON.parse(raw);
219
+ }
220
+ catch (_a) {
221
+ return;
222
+ }
223
+ if (!payload || payload.originInstanceId === this.instanceId) {
224
+ return;
225
+ }
226
+ // The version is only a watermark, so the lazy check does not re-clear a
227
+ // cache this message already fixed selectively. The invalidation itself is
228
+ // applied unconditionally: dropping an out-of-order message — this pod may
229
+ // have bumped past it on a write of its own — would leave the slug stale
230
+ // here until its TTL, which is exactly the bug this whole path fixes.
231
+ if (Number.isFinite(payload.version)) {
232
+ this.localCacheVersion = Math.max(this.localCacheVersion, payload.version);
233
+ this.lastVersionCheckAt = Date.now();
234
+ }
235
+ const slugs = Array.isArray(payload.slugs) ? payload.slugs.filter(Boolean) : [];
236
+ if (!slugs.length) {
237
+ this.invalidateCache();
238
+ return;
239
+ }
240
+ for (const slug of slugs) {
241
+ this.invalidateCache(slug);
242
+ }
243
+ }
244
+ async ensureVersionState() {
245
+ // The row is created once and never removed; repeating the INSERT on every
246
+ // version check would double the queries of a path that runs every 5s.
247
+ if (this.versionStateEnsured) {
248
+ return;
249
+ }
250
+ await this.prisma.$executeRawUnsafe(`
251
+ INSERT INTO "setting_runtime_state" ("scope", "version", "updated_at")
252
+ VALUES ('${RUNTIME_STATE_SCOPE}', 0, NOW())
253
+ ON CONFLICT ("scope") DO NOTHING
254
+ `);
255
+ this.versionStateEnsured = true;
256
+ }
257
+ /** BIGINT comes back from `$queryRawUnsafe` as a `bigint`, not a number. */
258
+ parseVersionValue(value) {
259
+ if (typeof value === 'number') {
260
+ return value;
261
+ }
262
+ if (typeof value === 'bigint') {
263
+ return Number(value);
264
+ }
265
+ if (typeof value === 'string') {
266
+ return Number(value);
267
+ }
268
+ return 0;
269
+ }
270
+ async getCacheVersionFromDatabase() {
271
+ var _a;
272
+ await this.ensureVersionState();
273
+ const rows = await this.prisma.$queryRawUnsafe(`
274
+ SELECT "version"
275
+ FROM "setting_runtime_state"
276
+ WHERE "scope" = '${RUNTIME_STATE_SCOPE}'
277
+ LIMIT 1
278
+ `);
279
+ return this.parseVersionValue((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.version);
280
+ }
281
+ async syncCacheVersionFromDatabase() {
282
+ this.localCacheVersion = await this.getCacheVersionFromDatabase();
283
+ this.lastVersionCheckAt = Date.now();
284
+ }
285
+ async bumpCacheVersion() {
286
+ var _a;
287
+ await this.ensureVersionState();
288
+ const rows = await this.prisma.$queryRawUnsafe(`
289
+ UPDATE "setting_runtime_state"
290
+ SET "version" = "version" + 1,
291
+ "updated_at" = NOW()
292
+ WHERE "scope" = '${RUNTIME_STATE_SCOPE}'
293
+ RETURNING "version"
294
+ `);
295
+ const nextVersion = this.parseVersionValue((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.version);
296
+ this.localCacheVersion = nextVersion;
297
+ this.lastVersionCheckAt = Date.now();
298
+ return nextVersion;
299
+ }
300
+ /**
301
+ * Catches up with writes from other pods when Redis is unavailable. Throttled
302
+ * and coalesced, so a burst of prompt resolutions costs one query at most.
303
+ */
304
+ async ensureCacheVersionFresh() {
305
+ const now = Date.now();
306
+ if (now - this.lastVersionCheckAt < this.versionCheckIntervalMs) {
307
+ return;
308
+ }
309
+ // `lastVersionCheckAt` only advances after the await, so parallel reads
310
+ // would each fire the same query and tie up the connection pool.
311
+ if (this.versionCheckInFlight) {
312
+ return this.versionCheckInFlight;
313
+ }
314
+ this.versionCheckInFlight = this.runVersionCheck(now).finally(() => {
315
+ this.versionCheckInFlight = null;
316
+ });
317
+ return this.versionCheckInFlight;
318
+ }
319
+ async runVersionCheck(startedAt) {
320
+ try {
321
+ const currentVersion = await this.getCacheVersionFromDatabase();
322
+ this.lastVersionCheckAt = startedAt;
323
+ if (currentVersion > this.localCacheVersion) {
324
+ this.localCacheVersion = currentVersion;
325
+ // This path knows a change happened but not which slugs it touched.
326
+ this.cache.clear();
327
+ }
328
+ }
329
+ catch (error) {
330
+ // Bookkeeping must never break prompt resolution: the resolver handles a
331
+ // throw by falling back to the code prompt, so a slow database would
332
+ // silently downgrade prompt quality. Serving the current cache is better.
333
+ this.lastVersionCheckAt = startedAt; // and do not hammer a sick database
334
+ this.logVersionCheckError(error);
85
335
  }
86
336
  }
337
+ logVersionCheckError(error) {
338
+ const now = Date.now();
339
+ if (now - this.lastVersionCheckErrorLogAt < 30000) {
340
+ return;
341
+ }
342
+ this.lastVersionCheckErrorLogAt = now;
343
+ this.logger.warn(`Failed to check ai instruction cache version: ${error instanceof Error ? error.message : String(error)}`);
344
+ }
345
+ /**
346
+ * Tells the other pods to drop these slugs. Bumps the database version first
347
+ * so pods without Redis still catch up on their next version check.
348
+ */
349
+ async publishInvalidation(slugs) {
350
+ var _a;
351
+ const filteredSlugs = Array.from(new Set(slugs.filter(Boolean)));
352
+ if (filteredSlugs.length === 0) {
353
+ return;
354
+ }
355
+ let version = this.localCacheVersion;
356
+ try {
357
+ version = await this.bumpCacheVersion();
358
+ }
359
+ catch (error) {
360
+ // The prompt write already committed; failing here must not turn a
361
+ // successful edit into a 500.
362
+ this.logger.warn(`Failed to bump ai instruction cache version: ${error instanceof Error ? error.message : String(error)}`);
363
+ }
364
+ // A stale version here is harmless: receivers take the max, and the lazy
365
+ // check compares against the database, not against this number.
366
+ await ((_a = this.pubsub) === null || _a === void 0 ? void 0 : _a.publish({
367
+ originInstanceId: this.instanceId,
368
+ version,
369
+ slugs: filteredSlugs,
370
+ }));
371
+ }
87
372
  // ── CRUD ─────────────────────────────────────────────────────────────────
88
- async list(paginationParams) {
373
+ async list(paginationParams, filters) {
89
374
  var _a;
90
375
  const page = Math.max(Number((paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.page) || 1), 1);
91
376
  const pageSize = Math.min(Math.max(Number((paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.pageSize) || 20), 1), 100);
92
377
  const offset = (page - 1) * pageSize;
93
378
  const search = String((paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.search) || '').trim();
94
- const whereClause = search
95
- ? api_prisma_1.Prisma.sql `WHERE (LOWER(slug) LIKE LOWER(${`%${search}%`}) OR LOWER(name) LIKE LOWER(${`%${search}%`}))`
379
+ const conditions = [];
380
+ if (search) {
381
+ conditions.push(api_prisma_1.Prisma.sql `(LOWER(slug) LIKE LOWER(${`%${search}%`}) OR LOWER(name) LIKE LOWER(${`%${search}%`}))`);
382
+ }
383
+ if (filters === null || filters === void 0 ? void 0 : filters.layer) {
384
+ conditions.push(api_prisma_1.Prisma.sql `layer = CAST(${filters.layer} AS ai_instruction_layer_enum)`);
385
+ }
386
+ if (filters === null || filters === void 0 ? void 0 : filters.module_slug) {
387
+ conditions.push(api_prisma_1.Prisma.sql `module_slug = ${filters.module_slug}`);
388
+ }
389
+ if ((filters === null || filters === void 0 ? void 0 : filters.is_active) !== undefined) {
390
+ conditions.push(api_prisma_1.Prisma.sql `is_active = ${filters.is_active}`);
391
+ }
392
+ const whereClause = conditions.length
393
+ ? api_prisma_1.Prisma.sql `WHERE ${api_prisma_1.Prisma.join(conditions, ' AND ')}`
96
394
  : api_prisma_1.Prisma.empty;
97
395
  const data = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
98
- SELECT id, slug, layer, name, content, variables_schema, locale, module_slug,
99
- is_active, version, created_at, updated_at
396
+ SELECT ${INSTRUCTION_COLUMNS}
100
397
  FROM ai_instruction
101
398
  ${whereClause}
102
399
  ORDER BY layer, slug
@@ -115,24 +412,105 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
115
412
  totalPages: Math.ceil(total / pageSize),
116
413
  };
117
414
  }
415
+ /** Distinct module slugs, for the module filter in the admin. */
416
+ async listModules() {
417
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
418
+ SELECT DISTINCT module_slug FROM ai_instruction
419
+ WHERE module_slug IS NOT NULL
420
+ ORDER BY module_slug
421
+ `);
422
+ return rows.map((row) => row.module_slug);
423
+ }
424
+ /**
425
+ * The prompts declared in code, paired with what the database currently holds.
426
+ *
427
+ * `dbMatchesFallback` is what lets the admin show "default" vs "customized"
428
+ * and offer "restore default"; it is also the fidelity check after a seed —
429
+ * every freshly seeded prompt must report `true`.
430
+ */
431
+ async listRegistry(moduleSlug) {
432
+ const definitions = (0, ai_prompt_registry_1.listAiPromptDefinitions)(moduleSlug);
433
+ const records = await this.getRecordsBySlugs(definitions.map((d) => d.slug));
434
+ return definitions.map((definition) => {
435
+ const record = records.get(definition.slug) || null;
436
+ return {
437
+ slug: definition.slug,
438
+ name: definition.name,
439
+ module_slug: definition.moduleSlug,
440
+ locale: definition.locale || 'pt',
441
+ fallback: definition.fallback,
442
+ variables: definition.variables,
443
+ security_sensitive: Boolean(definition.securitySensitive),
444
+ required_phrases: definition.requiredPhrases || [],
445
+ defaults: definition.defaults || {},
446
+ exists_in_db: Boolean(record),
447
+ db_matches_fallback: record ? record.content === definition.fallback : false,
448
+ };
449
+ });
450
+ }
451
+ /** Renders a draft without saving it, so the admin can check interpolation. */
452
+ previewPrompt(input) {
453
+ var _a, _b;
454
+ const definition = input.slug ? (0, ai_prompt_registry_1.getAiPromptDefinition)(input.slug) : undefined;
455
+ const schema = (_b = (_a = definition === null || definition === void 0 ? void 0 : definition.variables) !== null && _a !== void 0 ? _a : input.variables_schema) !== null && _b !== void 0 ? _b : null;
456
+ const validation = (0, ai_prompt_template_util_1.validateTemplate)(input.content, schema);
457
+ let rendered = '';
458
+ let renderError = null;
459
+ try {
460
+ rendered = (0, ai_prompt_template_util_1.renderTemplate)(input.content, input.variables || {});
461
+ }
462
+ catch (error) {
463
+ renderError = error instanceof Error ? error.message : String(error);
464
+ }
465
+ const warnings = [];
466
+ if (validation.unknownPlaceholders.length) {
467
+ warnings.push(`Variáveis não declaradas: ${validation.unknownPlaceholders.join(', ')}. ` +
468
+ 'Elas serão renderizadas literalmente.');
469
+ }
470
+ warnings.push(...this.missingPhraseWarnings(definition, input.content));
471
+ return {
472
+ rendered,
473
+ render_error: renderError,
474
+ char_count: rendered.length,
475
+ estimated_tokens: (0, ai_prompt_template_util_1.estimateTokens)(rendered),
476
+ missing_required: validation.missingRequired,
477
+ unknown_placeholders: validation.unknownPlaceholders,
478
+ unbalanced_blocks: validation.unbalancedBlocks,
479
+ warnings,
480
+ };
481
+ }
118
482
  async getById(id) {
119
483
  const record = await this.findById(id);
120
484
  if (!record)
121
485
  throw new common_1.NotFoundException(`AI instruction ${id} not found.`);
122
486
  return record;
123
487
  }
124
- async getBySlug(slug) {
125
- const record = await this.findActiveBySlug(slug);
488
+ /**
489
+ * Inactive records are returned on purpose: the admin needs to open one to
490
+ * reactivate it. Pass `activeOnly` for the resolution path.
491
+ */
492
+ async getBySlug(slug, activeOnly = false) {
493
+ const record = activeOnly
494
+ ? await this.findActiveBySlug(slug)
495
+ : await this.findBySlug(slug);
126
496
  if (!record)
127
497
  throw new common_1.NotFoundException(`AI instruction "${slug}" not found.`);
128
498
  return record;
129
499
  }
130
500
  async create(dto, createdById) {
131
- var _a;
501
+ var _a, _b, _c, _d, _e;
132
502
  const locale = dto.locale || 'en';
133
503
  const isActive = (_a = dto.is_active) !== null && _a !== void 0 ? _a : true;
504
+ const existing = await this.findBySlug(dto.slug);
505
+ if (existing) {
506
+ throw new common_1.ConflictException(`AI instruction "${dto.slug}" already exists.`);
507
+ }
508
+ this.validateContent(dto.slug, dto.content, {
509
+ fallbackSchema: (_b = dto.variables_schema) !== null && _b !== void 0 ? _b : null,
510
+ allowMissingVariables: dto.allow_missing_variables,
511
+ });
134
512
  await this.prisma.$executeRaw `
135
- INSERT INTO ai_instruction (slug, layer, name, content, variables_schema, locale, module_slug, is_active, version)
513
+ INSERT INTO ai_instruction (slug, layer, name, content, variables_schema, locale, module_slug, is_active, version, model, temperature, max_tokens)
136
514
  VALUES (
137
515
  ${dto.slug},
138
516
  CAST(${dto.layer} AS ai_instruction_layer_enum),
@@ -142,23 +520,50 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
142
520
  ${locale},
143
521
  ${dto.module_slug || null},
144
522
  ${isActive},
145
- 1
523
+ 1,
524
+ ${(_c = dto.model) !== null && _c !== void 0 ? _c : null},
525
+ ${(_d = dto.temperature) !== null && _d !== void 0 ? _d : null},
526
+ ${(_e = dto.max_tokens) !== null && _e !== void 0 ? _e : null}
146
527
  )
147
528
  `;
148
- const created = await this.findActiveBySlug(dto.slug);
529
+ const created = await this.findBySlug(dto.slug);
149
530
  // Record version 1
150
531
  if (created) {
151
532
  await this.saveVersion(created.id, 1, dto.content, 'Initial version', createdById);
152
533
  }
534
+ // Negative cache entries for this slug must go, otherwise the prompt stays
535
+ // invisible to the resolver until the TTL expires. Kept separate from the
536
+ // publish below so a Redis outage never leaves this pod itself stale.
537
+ this.invalidateCache(dto.slug);
538
+ await this.publishInvalidation([dto.slug]);
153
539
  return created;
154
540
  }
155
541
  async update(id, dto, updatedById) {
156
542
  var _a, _b, _c, _d;
157
543
  const current = await this.getById(id);
544
+ // Locked records are security-sensitive prompts (the essay-grading
545
+ // injection defence). Still editable, but never by accident.
546
+ if (current.is_locked && !dto.acknowledge_security_review) {
547
+ throw new common_1.ConflictException(`AI instruction "${current.slug}" is a security-sensitive prompt. ` +
548
+ 'Send acknowledge_security_review=true to confirm you reviewed the change.');
549
+ }
158
550
  const newContent = (_a = dto.content) !== null && _a !== void 0 ? _a : current.content;
159
551
  const newVersion = dto.content && dto.content !== current.content
160
552
  ? current.version + 1
161
553
  : current.version;
554
+ const warnings = dto.content !== undefined
555
+ ? this.validateContent(current.slug, dto.content, {
556
+ fallbackSchema: current.variables_schema,
557
+ allowMissingVariables: dto.allow_missing_variables,
558
+ })
559
+ : [];
560
+ // Losing every guard phrase is recorded in the immutable version row, not
561
+ // just in the log — the resolver will also refuse the stored copy.
562
+ const changeNote = warnings.length
563
+ ? [dto.change_note, `[warnings: ${warnings.join(' | ')}]`].filter(Boolean).join(' ').slice(0, 500)
564
+ : dto.change_note;
565
+ // `undefined` means "leave alone", `null` means "clear" — `??` collapses the
566
+ // two, so the model params use an explicit undefined check.
162
567
  await this.prisma.$executeRaw `
163
568
  UPDATE ai_instruction
164
569
  SET
@@ -168,16 +573,20 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
168
573
  locale = ${(_c = dto.locale) !== null && _c !== void 0 ? _c : current.locale},
169
574
  module_slug = ${dto.module_slug !== undefined ? dto.module_slug : current.module_slug},
170
575
  is_active = ${(_d = dto.is_active) !== null && _d !== void 0 ? _d : current.is_active},
576
+ model = ${dto.model !== undefined ? dto.model : current.model},
577
+ temperature = ${dto.temperature !== undefined ? dto.temperature : current.temperature},
578
+ max_tokens = ${dto.max_tokens !== undefined ? dto.max_tokens : current.max_tokens},
171
579
  version = ${newVersion},
172
580
  updated_at = NOW()
173
581
  WHERE id = ${id}
174
582
  `;
175
583
  // Save new version if content changed
176
584
  if (dto.content && dto.content !== current.content) {
177
- await this.saveVersion(id, newVersion, newContent, dto.change_note, updatedById);
585
+ await this.saveVersion(id, newVersion, newContent, changeNote, updatedById);
178
586
  }
179
587
  this.invalidateCache(current.slug);
180
- return this.getById(id);
588
+ await this.publishInvalidation([current.slug]);
589
+ return Object.assign(Object.assign({}, (await this.getById(id))), { warnings });
181
590
  }
182
591
  async delete({ ids }) {
183
592
  const existing = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
@@ -191,6 +600,8 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
191
600
  DELETE FROM ai_instruction WHERE id IN (${api_prisma_1.Prisma.join(ids)})
192
601
  `;
193
602
  existing.forEach((r) => this.invalidateCache(r.slug));
603
+ // One bump and one message for the whole batch.
604
+ await this.publishInvalidation(existing.map((r) => r.slug));
194
605
  return { count: ids.length };
195
606
  }
196
607
  async listVersions(id) {
@@ -223,48 +634,110 @@ let AiInstructionService = AiInstructionService_1 = class AiInstructionService {
223
634
  `;
224
635
  await this.saveVersion(id, newVersion, target.content, `Restored from version ${version}`, restoredById);
225
636
  this.invalidateCache(current.slug);
637
+ await this.publishInvalidation([current.slug]);
226
638
  return this.getById(id);
227
639
  }
228
640
  // ── Private helpers ───────────────────────────────────────────────────────
641
+ /**
642
+ * Rejects content that would break at render time, and returns non-fatal
643
+ * warnings for the caller to surface.
644
+ *
645
+ * An unclosed block is a hard 422: it silently swallows the rest of the
646
+ * prompt. A removed required variable is also a 422, overridable with
647
+ * `allow_missing_variables` — sometimes a rewrite genuinely no longer needs a
648
+ * variable. An unknown placeholder is only a warning: it renders literally,
649
+ * which is ugly but harmless.
650
+ */
651
+ validateContent(slug, content, options) {
652
+ var _a, _b;
653
+ const definition = (0, ai_prompt_registry_1.getAiPromptDefinition)(slug);
654
+ const schema = (_b = (_a = definition === null || definition === void 0 ? void 0 : definition.variables) !== null && _a !== void 0 ? _a : options.fallbackSchema) !== null && _b !== void 0 ? _b : null;
655
+ const { missingRequired, unknownPlaceholders, unbalancedBlocks } = (0, ai_prompt_template_util_1.validateTemplate)(content, schema);
656
+ if (unbalancedBlocks.length) {
657
+ throw new common_1.UnprocessableEntityException(`Bloco de template não fechado: ${unbalancedBlocks
658
+ .map((name) => `{{#${name}}}`)
659
+ .join(', ')}. Isso descartaria o resto do prompt.`);
660
+ }
661
+ if (missingRequired.length && !options.allowMissingVariables) {
662
+ throw new common_1.UnprocessableEntityException(`Variáveis obrigatórias ausentes do conteúdo: ${missingRequired.join(', ')}. ` +
663
+ 'Envie allow_missing_variables=true para salvar mesmo assim.');
664
+ }
665
+ const warnings = [];
666
+ if (missingRequired.length) {
667
+ warnings.push(`missing-variables: ${missingRequired.join(', ')}`);
668
+ }
669
+ if (unknownPlaceholders.length) {
670
+ warnings.push(`unknown-variables: ${unknownPlaceholders.join(', ')}`);
671
+ }
672
+ warnings.push(...this.missingPhraseWarnings(definition, content));
673
+ return warnings;
674
+ }
675
+ /**
676
+ * Guard phrases are the runtime protection for security-sensitive prompts: if
677
+ * the stored content contains none of them, `AiPromptResolverService` discards
678
+ * it. Warn loudly here so the editor learns it before the first graded essay.
679
+ */
680
+ missingPhraseWarnings(definition, content) {
681
+ const phrases = definition === null || definition === void 0 ? void 0 : definition.requiredPhrases;
682
+ if (!(phrases === null || phrases === void 0 ? void 0 : phrases.length))
683
+ return [];
684
+ const missing = phrases.filter((phrase) => !content.includes(phrase));
685
+ if (!missing.length)
686
+ return [];
687
+ const hasAny = missing.length < phrases.length;
688
+ const warning = `security-phrases-removed: ${missing.join(', ')}`;
689
+ if (hasAny) {
690
+ this.logger.warn(`AI prompt "${definition.slug}" lost safety phrases: ${missing.join(', ')}`);
691
+ return [warning];
692
+ }
693
+ this.logger.error(`AI prompt "${definition.slug}" lost ALL of its safety phrases; the resolver ` +
694
+ 'will ignore the stored content and use the code fallback.');
695
+ return [`${warning} (todas — o prompt do banco será ignorado em runtime)`];
696
+ }
229
697
  async findById(id) {
230
- const rows = await this.prisma.$queryRaw `
231
- SELECT id, slug, layer, name, content, variables_schema, locale, module_slug,
232
- is_active, version, created_at, updated_at
698
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
699
+ SELECT ${INSTRUCTION_COLUMNS}
233
700
  FROM ai_instruction WHERE id = ${id} LIMIT 1
234
- `;
701
+ `);
702
+ return (rows === null || rows === void 0 ? void 0 : rows[0]) || null;
703
+ }
704
+ async findBySlug(slug) {
705
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
706
+ SELECT ${INSTRUCTION_COLUMNS}
707
+ FROM ai_instruction WHERE slug = ${slug} LIMIT 1
708
+ `);
235
709
  return (rows === null || rows === void 0 ? void 0 : rows[0]) || null;
236
710
  }
237
711
  async findActiveBySlug(slug) {
238
- const rows = await this.prisma.$queryRaw `
239
- SELECT id, slug, layer, name, content, variables_schema, locale, module_slug,
240
- is_active, version, created_at, updated_at
712
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
713
+ SELECT ${INSTRUCTION_COLUMNS}
241
714
  FROM ai_instruction WHERE slug = ${slug} AND is_active = TRUE LIMIT 1
242
- `;
715
+ `);
243
716
  return (rows === null || rows === void 0 ? void 0 : rows[0]) || null;
244
717
  }
245
718
  async findActiveByLayer(layer, moduleSlug) {
246
719
  if (moduleSlug) {
247
- const rows = await this.prisma.$queryRaw `
248
- SELECT id, slug, layer, name, content, variables_schema, locale, module_slug,
249
- is_active, version, created_at, updated_at
720
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
721
+ SELECT ${INSTRUCTION_COLUMNS}
250
722
  FROM ai_instruction
251
723
  WHERE layer = CAST(${layer} AS ai_instruction_layer_enum)
252
724
  AND module_slug = ${moduleSlug}
253
725
  AND is_active = TRUE
726
+ ORDER BY id
254
727
  LIMIT 1
255
- `;
728
+ `);
256
729
  if (rows === null || rows === void 0 ? void 0 : rows[0])
257
730
  return rows[0];
258
731
  }
259
- const rows = await this.prisma.$queryRaw `
260
- SELECT id, slug, layer, name, content, variables_schema, locale, module_slug,
261
- is_active, version, created_at, updated_at
732
+ const rows = await this.prisma.$queryRaw(api_prisma_1.Prisma.sql `
733
+ SELECT ${INSTRUCTION_COLUMNS}
262
734
  FROM ai_instruction
263
735
  WHERE layer = CAST(${layer} AS ai_instruction_layer_enum)
264
736
  AND module_slug IS NULL
265
737
  AND is_active = TRUE
738
+ ORDER BY id
266
739
  LIMIT 1
267
- `;
740
+ `);
268
741
  return (rows === null || rows === void 0 ? void 0 : rows[0]) || null;
269
742
  }
270
743
  async saveVersion(instructionId, version, content, changeNote, createdById) {