@hed-hog/core 0.0.399 → 0.0.401

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 (815) hide show
  1. package/dist/ai/ai-agent.sort.d.ts +6 -0
  2. package/dist/ai/ai-agent.sort.d.ts.map +1 -0
  3. package/dist/ai/ai-agent.sort.js +21 -0
  4. package/dist/ai/ai-agent.sort.js.map +1 -0
  5. package/dist/ai/ai.controller.d.ts +6 -4
  6. package/dist/ai/ai.controller.d.ts.map +1 -1
  7. package/dist/ai/ai.service.d.ts +121 -6
  8. package/dist/ai/ai.service.d.ts.map +1 -1
  9. package/dist/ai/ai.service.js +355 -160
  10. package/dist/ai/ai.service.js.map +1 -1
  11. package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
  12. package/dist/ai-instruction/ai-instruction.service.js +26 -23
  13. package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
  14. package/dist/ai-instruction/ai-instruction.sort.d.ts +16 -0
  15. package/dist/ai-instruction/ai-instruction.sort.d.ts.map +1 -0
  16. package/dist/ai-instruction/ai-instruction.sort.js +32 -0
  17. package/dist/ai-instruction/ai-instruction.sort.js.map +1 -0
  18. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +12 -0
  19. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -1
  20. package/dist/ai-instruction/ai-prompt-resolver.service.js +26 -0
  21. package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -1
  22. package/dist/auth/auth.controller.d.ts +24 -8
  23. package/dist/auth/auth.controller.d.ts.map +1 -1
  24. package/dist/auth/auth.module.d.ts.map +1 -1
  25. package/dist/auth/auth.module.js +8 -1
  26. package/dist/auth/auth.module.js.map +1 -1
  27. package/dist/auth/auth.service.d.ts +72 -25
  28. package/dist/auth/auth.service.d.ts.map +1 -1
  29. package/dist/auth/auth.service.js +41 -4
  30. package/dist/auth/auth.service.js.map +1 -1
  31. package/dist/auth/guards/auth.guard.d.ts +3 -1
  32. package/dist/auth/guards/auth.guard.d.ts.map +1 -1
  33. package/dist/auth/guards/auth.guard.js +12 -3
  34. package/dist/auth/guards/auth.guard.js.map +1 -1
  35. package/dist/authorize/authorize.controller.d.ts +29 -5
  36. package/dist/authorize/authorize.controller.d.ts.map +1 -1
  37. package/dist/authorize/authorize.controller.js +120 -13
  38. package/dist/authorize/authorize.controller.js.map +1 -1
  39. package/dist/authorize/authorize.errors.d.ts +34 -0
  40. package/dist/authorize/authorize.errors.d.ts.map +1 -0
  41. package/dist/authorize/authorize.errors.js +37 -0
  42. package/dist/authorize/authorize.errors.js.map +1 -0
  43. package/dist/authorize/authorize.module.d.ts.map +1 -1
  44. package/dist/authorize/authorize.module.js +6 -1
  45. package/dist/authorize/authorize.module.js.map +1 -1
  46. package/dist/authorize/authorize.service.d.ts +77 -3
  47. package/dist/authorize/authorize.service.d.ts.map +1 -1
  48. package/dist/authorize/authorize.service.js +212 -21
  49. package/dist/authorize/authorize.service.js.map +1 -1
  50. package/dist/authorize/dto/authorize-info.dto.d.ts +10 -1
  51. package/dist/authorize/dto/authorize-info.dto.d.ts.map +1 -1
  52. package/dist/authorize/dto/authorize-info.dto.js +16 -1
  53. package/dist/authorize/dto/authorize-info.dto.js.map +1 -1
  54. package/dist/authorize/dto/consent.dto.d.ts +10 -1
  55. package/dist/authorize/dto/consent.dto.d.ts.map +1 -1
  56. package/dist/authorize/dto/consent.dto.js +16 -1
  57. package/dist/authorize/dto/consent.dto.js.map +1 -1
  58. package/dist/authorize/dto/token.dto.d.ts +12 -0
  59. package/dist/authorize/dto/token.dto.d.ts.map +1 -1
  60. package/dist/authorize/dto/token.dto.js +21 -1
  61. package/dist/authorize/dto/token.dto.js.map +1 -1
  62. package/dist/authorize/oauth-exception.filter.d.ts +17 -0
  63. package/dist/authorize/oauth-exception.filter.d.ts.map +1 -0
  64. package/dist/authorize/oauth-exception.filter.js +54 -0
  65. package/dist/authorize/oauth-exception.filter.js.map +1 -0
  66. package/dist/authorize/oauth-metadata.service.d.ts +39 -0
  67. package/dist/authorize/oauth-metadata.service.d.ts.map +1 -0
  68. package/dist/authorize/oauth-metadata.service.js +81 -0
  69. package/dist/authorize/oauth-metadata.service.js.map +1 -0
  70. package/dist/authorize/well-known.controller.d.ts +67 -0
  71. package/dist/authorize/well-known.controller.d.ts.map +1 -0
  72. package/dist/authorize/well-known.controller.js +126 -0
  73. package/dist/authorize/well-known.controller.js.map +1 -0
  74. package/dist/captcha/captcha.service.d.ts +32 -2
  75. package/dist/captcha/captcha.service.d.ts.map +1 -1
  76. package/dist/captcha/captcha.service.js +85 -12
  77. package/dist/captcha/captcha.service.js.map +1 -1
  78. package/dist/challenge/challenge.service.d.ts +2 -2
  79. package/dist/core.module.d.ts.map +1 -1
  80. package/dist/core.module.js +9 -0
  81. package/dist/core.module.js.map +1 -1
  82. package/dist/dashboard/dashboard/dashboard.controller.d.ts +9 -9
  83. package/dist/dashboard/dashboard/dashboard.service.d.ts +9 -9
  84. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +3 -3
  85. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +3 -3
  86. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +3 -3
  87. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +3 -3
  88. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
  89. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js +2 -4
  90. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js.map +1 -1
  91. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts +8 -0
  92. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts.map +1 -0
  93. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js +18 -0
  94. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js.map +1 -0
  95. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
  96. package/dist/dashboard/dashboard-item/dashboard-item.service.js +2 -4
  97. package/dist/dashboard/dashboard-item/dashboard-item.service.js.map +1 -1
  98. package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts +9 -0
  99. package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts.map +1 -0
  100. package/dist/dashboard/dashboard-item/dashboard-item.sort.js +19 -0
  101. package/dist/dashboard/dashboard-item/dashboard-item.sort.js.map +1 -0
  102. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +3 -3
  103. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +3 -3
  104. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
  105. package/dist/dashboard/dashboard-role/dashboard-role.service.js +2 -4
  106. package/dist/dashboard/dashboard-role/dashboard-role.service.js.map +1 -1
  107. package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts +8 -0
  108. package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts.map +1 -0
  109. package/dist/dashboard/dashboard-role/dashboard-role.sort.js +16 -0
  110. package/dist/dashboard/dashboard-role/dashboard-role.sort.js.map +1 -0
  111. package/dist/document-kit/document-kit.module.d.ts +3 -0
  112. package/dist/document-kit/document-kit.module.d.ts.map +1 -0
  113. package/dist/document-kit/document-kit.module.js +24 -0
  114. package/dist/document-kit/document-kit.module.js.map +1 -0
  115. package/dist/document-kit/document-kit.registry.d.ts +55 -0
  116. package/dist/document-kit/document-kit.registry.d.ts.map +1 -0
  117. package/dist/document-kit/document-kit.registry.js +91 -0
  118. package/dist/document-kit/document-kit.registry.js.map +1 -0
  119. package/dist/document-kit/document-kit.service.d.ts +49 -0
  120. package/dist/document-kit/document-kit.service.d.ts.map +1 -0
  121. package/dist/document-kit/document-kit.service.js +135 -0
  122. package/dist/document-kit/document-kit.service.js.map +1 -0
  123. package/dist/file/file-upload-ticket.service.d.ts +160 -0
  124. package/dist/file/file-upload-ticket.service.d.ts.map +1 -0
  125. package/dist/file/file-upload-ticket.service.js +382 -0
  126. package/dist/file/file-upload-ticket.service.js.map +1 -0
  127. package/dist/file/file.controller.d.ts +24 -1
  128. package/dist/file/file.controller.d.ts.map +1 -1
  129. package/dist/file/file.controller.js +63 -2
  130. package/dist/file/file.controller.js.map +1 -1
  131. package/dist/file/file.module.d.ts.map +1 -1
  132. package/dist/file/file.module.js +14 -2
  133. package/dist/file/file.module.js.map +1 -1
  134. package/dist/file/file.service.d.ts +197 -7
  135. package/dist/file/file.service.d.ts.map +1 -1
  136. package/dist/file/file.service.js +438 -78
  137. package/dist/file/file.service.js.map +1 -1
  138. package/dist/file/filename-encoding.util.d.ts +24 -0
  139. package/dist/file/filename-encoding.util.d.ts.map +1 -0
  140. package/dist/file/filename-encoding.util.js +63 -0
  141. package/dist/file/filename-encoding.util.js.map +1 -0
  142. package/dist/file/image-optimization.service.d.ts +27 -0
  143. package/dist/file/image-optimization.service.d.ts.map +1 -1
  144. package/dist/file/image-optimization.service.js +63 -14
  145. package/dist/file/image-optimization.service.js.map +1 -1
  146. package/dist/file/mcp-file-source.schema.d.ts +33 -0
  147. package/dist/file/mcp-file-source.schema.d.ts.map +1 -0
  148. package/dist/file/mcp-file-source.schema.js +78 -0
  149. package/dist/file/mcp-file-source.schema.js.map +1 -0
  150. package/dist/file/mcp-file-source.service.d.ts +124 -0
  151. package/dist/file/mcp-file-source.service.d.ts.map +1 -0
  152. package/dist/file/mcp-file-source.service.js +262 -0
  153. package/dist/file/mcp-file-source.service.js.map +1 -0
  154. package/dist/file/mimetype-sniff.util.d.ts +62 -0
  155. package/dist/file/mimetype-sniff.util.d.ts.map +1 -0
  156. package/dist/file/mimetype-sniff.util.js +226 -0
  157. package/dist/file/mimetype-sniff.util.js.map +1 -0
  158. package/dist/file/remote-fetch.util.d.ts +35 -0
  159. package/dist/file/remote-fetch.util.d.ts.map +1 -0
  160. package/dist/file/remote-fetch.util.js +236 -0
  161. package/dist/file/remote-fetch.util.js.map +1 -0
  162. package/dist/impersonation/dto/start-impersonation.dto.d.ts +4 -1
  163. package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -1
  164. package/dist/impersonation/dto/start-impersonation.dto.js +1 -1
  165. package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -1
  166. package/dist/impersonation/impersonation.service.d.ts +8 -3
  167. package/dist/impersonation/impersonation.service.d.ts.map +1 -1
  168. package/dist/impersonation/impersonation.service.js +14 -4
  169. package/dist/impersonation/impersonation.service.js.map +1 -1
  170. package/dist/incident/incident.controller.d.ts +2 -1
  171. package/dist/incident/incident.controller.d.ts.map +1 -1
  172. package/dist/incident/incident.controller.js +10 -6
  173. package/dist/incident/incident.controller.js.map +1 -1
  174. package/dist/incident/incident.service.d.ts +2 -0
  175. package/dist/incident/incident.service.d.ts.map +1 -1
  176. package/dist/incident/incident.service.js +4 -0
  177. package/dist/incident/incident.service.js.map +1 -1
  178. package/dist/index.d.ts +22 -0
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +22 -0
  181. package/dist/index.js.map +1 -1
  182. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  183. package/dist/integration-profile/integration-profile.secrets.js +28 -0
  184. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  185. package/dist/integration-profile/integration-profile.service.d.ts +0 -13
  186. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  187. package/dist/integration-profile/integration-profile.service.js +5 -40
  188. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  189. package/dist/integration-profile/integration-profile.utils.js +5 -5
  190. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  191. package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -1
  192. package/dist/integration-profile/testers/ai.testers.js +46 -8
  193. package/dist/integration-profile/testers/ai.testers.js.map +1 -1
  194. package/dist/integration-profile/testers/index.d.ts.map +1 -1
  195. package/dist/integration-profile/testers/index.js +2 -0
  196. package/dist/integration-profile/testers/index.js.map +1 -1
  197. package/dist/integration-profile/testers/shipping.testers.d.ts +3 -0
  198. package/dist/integration-profile/testers/shipping.testers.d.ts.map +1 -0
  199. package/dist/integration-profile/testers/shipping.testers.js +71 -0
  200. package/dist/integration-profile/testers/shipping.testers.js.map +1 -0
  201. package/dist/locale/locale.controller.d.ts +1 -1
  202. package/dist/locale/locale.service.d.ts +1 -1
  203. package/dist/mail/dto/send.dto.d.ts +6 -1
  204. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  205. package/dist/mail/dto/send.dto.js.map +1 -1
  206. package/dist/mail/mail.service.d.ts +9 -0
  207. package/dist/mail/mail.service.d.ts.map +1 -1
  208. package/dist/mail/mail.service.js +34 -14
  209. package/dist/mail/mail.service.js.map +1 -1
  210. package/dist/mail-sent/mail-sent.controller.d.ts +1 -1
  211. package/dist/mail-sent/mail-sent.service.d.ts +1 -1
  212. package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
  213. package/dist/mail-sent/mail-sent.service.js +2 -1
  214. package/dist/mail-sent/mail-sent.service.js.map +1 -1
  215. package/dist/mail-sent/mail-sent.sort.d.ts +9 -0
  216. package/dist/mail-sent/mail-sent.sort.d.ts.map +1 -0
  217. package/dist/mail-sent/mail-sent.sort.js +19 -0
  218. package/dist/mail-sent/mail-sent.sort.js.map +1 -0
  219. package/dist/mcp/filters/mcp-challenge.filter.d.ts +20 -0
  220. package/dist/mcp/filters/mcp-challenge.filter.d.ts.map +1 -0
  221. package/dist/mcp/filters/mcp-challenge.filter.js +69 -0
  222. package/dist/mcp/filters/mcp-challenge.filter.js.map +1 -0
  223. package/dist/mcp/guards/mcp-auth.guard.d.ts +4 -1
  224. package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
  225. package/dist/mcp/guards/mcp-auth.guard.js +19 -5
  226. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
  227. package/dist/mcp/guards/mcp-permission.guard.d.ts +25 -3
  228. package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -1
  229. package/dist/mcp/guards/mcp-permission.guard.js +46 -26
  230. package/dist/mcp/guards/mcp-permission.guard.js.map +1 -1
  231. package/dist/mcp/mcp-audit.service.d.ts +17 -0
  232. package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
  233. package/dist/mcp/mcp-audit.service.js +32 -3
  234. package/dist/mcp/mcp-audit.service.js.map +1 -1
  235. package/dist/mcp/mcp-permission.service.d.ts +64 -0
  236. package/dist/mcp/mcp-permission.service.d.ts.map +1 -0
  237. package/dist/mcp/mcp-permission.service.js +178 -0
  238. package/dist/mcp/mcp-permission.service.js.map +1 -0
  239. package/dist/mcp/mcp-server.service.d.ts +3 -1
  240. package/dist/mcp/mcp-server.service.d.ts.map +1 -1
  241. package/dist/mcp/mcp-server.service.js +36 -15
  242. package/dist/mcp/mcp-server.service.js.map +1 -1
  243. package/dist/mcp/mcp.controller.d.ts.map +1 -1
  244. package/dist/mcp/mcp.controller.js +10 -2
  245. package/dist/mcp/mcp.controller.js.map +1 -1
  246. package/dist/mcp/mcp.module.d.ts.map +1 -1
  247. package/dist/mcp/mcp.module.js +7 -1
  248. package/dist/mcp/mcp.module.js.map +1 -1
  249. package/dist/mcp/tools/core-access-log.mcp-tools.d.ts +17 -0
  250. package/dist/mcp/tools/core-access-log.mcp-tools.d.ts.map +1 -0
  251. package/dist/mcp/tools/core-access-log.mcp-tools.js +74 -0
  252. package/dist/mcp/tools/core-access-log.mcp-tools.js.map +1 -0
  253. package/dist/mcp/tools/core-ai.mcp-tools.js +2 -9
  254. package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -1
  255. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +1 -1
  256. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -1
  257. package/dist/mcp/tools/core-dashboard.mcp-tools.js +2 -9
  258. package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -1
  259. package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -1
  260. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +2 -10
  261. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -1
  262. package/dist/mcp/tools/core-files.mcp-tools.d.ts +17 -5
  263. package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -1
  264. package/dist/mcp/tools/core-files.mcp-tools.js +186 -24
  265. package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -1
  266. package/dist/mcp/tools/core-integration-events.mcp-tools.js +2 -9
  267. package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -1
  268. package/dist/mcp/tools/core-mail-sent.mcp-tools.js +2 -14
  269. package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -1
  270. package/dist/mcp/tools/core-mail.mcp-tools.js +2 -9
  271. package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -1
  272. package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -1
  273. package/dist/mcp/tools/core-menus.mcp-tools.js +2 -10
  274. package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -1
  275. package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -1
  276. package/dist/mcp/tools/core-notifications.mcp-tools.js +0 -1
  277. package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -1
  278. package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -1
  279. package/dist/mcp/tools/core-roles.mcp-tools.js +2 -13
  280. package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -1
  281. package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -1
  282. package/dist/mcp/tools/core-routes.mcp-tools.js +2 -11
  283. package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -1
  284. package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -1
  285. package/dist/mcp/tools/core-screens.mcp-tools.js +2 -11
  286. package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -1
  287. package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -1
  288. package/dist/mcp/tools/core-sessions.mcp-tools.js +0 -2
  289. package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -1
  290. package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
  291. package/dist/mcp/tools/core-settings.mcp-tools.js +2 -10
  292. package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
  293. package/dist/mcp/tools/core-users.mcp-tools.js +2 -9
  294. package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -1
  295. package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -1
  296. package/dist/mcp/tools/core-webhooks.mcp-tools.js +2 -10
  297. package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -1
  298. package/dist/mcp/types/mcp-context.type.d.ts +9 -0
  299. package/dist/mcp/types/mcp-context.type.d.ts.map +1 -1
  300. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  301. package/dist/mcp-chat/mcp-chat.service.js +8 -0
  302. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  303. package/dist/meeting/meeting-provider.registry.d.ts +187 -0
  304. package/dist/meeting/meeting-provider.registry.d.ts.map +1 -1
  305. package/dist/meeting/meeting-provider.registry.js.map +1 -1
  306. package/dist/meeting/meeting.constants.d.ts +70 -0
  307. package/dist/meeting/meeting.constants.d.ts.map +1 -1
  308. package/dist/meeting/meeting.constants.js +9 -1
  309. package/dist/meeting/meeting.constants.js.map +1 -1
  310. package/dist/menu/menu.service.d.ts.map +1 -1
  311. package/dist/menu/menu.service.js +29 -9
  312. package/dist/menu/menu.service.js.map +1 -1
  313. package/dist/message-template/dto/update-message-template.dto.d.ts +18 -0
  314. package/dist/message-template/dto/update-message-template.dto.d.ts.map +1 -0
  315. package/dist/message-template/dto/update-message-template.dto.js +38 -0
  316. package/dist/message-template/dto/update-message-template.dto.js.map +1 -0
  317. package/dist/message-template/message-template-admin.service.d.ts +70 -0
  318. package/dist/message-template/message-template-admin.service.d.ts.map +1 -0
  319. package/dist/message-template/message-template-admin.service.js +226 -0
  320. package/dist/message-template/message-template-admin.service.js.map +1 -0
  321. package/dist/message-template/message-template.controller.d.ts +29 -0
  322. package/dist/message-template/message-template.controller.d.ts.map +1 -0
  323. package/dist/message-template/message-template.controller.js +101 -0
  324. package/dist/message-template/message-template.controller.js.map +1 -0
  325. package/dist/message-template/message-template.module.d.ts +10 -0
  326. package/dist/message-template/message-template.module.d.ts.map +1 -0
  327. package/dist/message-template/message-template.module.js +33 -0
  328. package/dist/message-template/message-template.module.js.map +1 -0
  329. package/dist/message-template/message-template.registry.d.ts +55 -0
  330. package/dist/message-template/message-template.registry.d.ts.map +1 -0
  331. package/dist/message-template/message-template.registry.js +64 -0
  332. package/dist/message-template/message-template.registry.js.map +1 -0
  333. package/dist/message-template/message-template.service.d.ts +59 -0
  334. package/dist/message-template/message-template.service.d.ts.map +1 -0
  335. package/dist/message-template/message-template.service.js +166 -0
  336. package/dist/message-template/message-template.service.js.map +1 -0
  337. package/dist/notification/notification.constants.d.ts +11 -0
  338. package/dist/notification/notification.constants.d.ts.map +1 -0
  339. package/dist/notification/notification.constants.js +14 -0
  340. package/dist/notification/notification.constants.js.map +1 -0
  341. package/dist/notification/notification.controller.d.ts +20 -20
  342. package/dist/notification/notification.module.d.ts.map +1 -1
  343. package/dist/notification/notification.module.js +3 -0
  344. package/dist/notification/notification.module.js.map +1 -1
  345. package/dist/notification/notification.service.d.ts +33 -21
  346. package/dist/notification/notification.service.d.ts.map +1 -1
  347. package/dist/notification/notification.service.js +36 -2
  348. package/dist/notification/notification.service.js.map +1 -1
  349. package/dist/oauth/oauth-token-broker.service.d.ts +50 -1
  350. package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -1
  351. package/dist/oauth/oauth-token-broker.service.js +105 -3
  352. package/dist/oauth/oauth-token-broker.service.js.map +1 -1
  353. package/dist/oauth/oauth.controller.d.ts +4 -6
  354. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  355. package/dist/oauth/oauth.controller.js +0 -1
  356. package/dist/oauth/oauth.controller.js.map +1 -1
  357. package/dist/oauth/oauth.errors.d.ts +15 -1
  358. package/dist/oauth/oauth.errors.d.ts.map +1 -1
  359. package/dist/oauth/oauth.errors.js +9 -1
  360. package/dist/oauth/oauth.errors.js.map +1 -1
  361. package/dist/oauth/oauth.module.d.ts.map +1 -1
  362. package/dist/oauth/oauth.module.js +6 -1
  363. package/dist/oauth/oauth.module.js.map +1 -1
  364. package/dist/oauth/oauth.service.d.ts +25 -5
  365. package/dist/oauth/oauth.service.d.ts.map +1 -1
  366. package/dist/oauth/oauth.service.js +63 -27
  367. package/dist/oauth/oauth.service.js.map +1 -1
  368. package/dist/oauth/providers/abstract.provider.d.ts +10 -0
  369. package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
  370. package/dist/oauth/providers/abstract.provider.js +39 -12
  371. package/dist/oauth/providers/abstract.provider.js.map +1 -1
  372. package/dist/oauth/providers/github.provider.d.ts +1 -1
  373. package/dist/oauth/providers/github.provider.d.ts.map +1 -1
  374. package/dist/oauth/providers/github.provider.js +48 -22
  375. package/dist/oauth/providers/github.provider.js.map +1 -1
  376. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +6 -0
  377. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  378. package/dist/oauth/providers/microsoft-entra-id.provider.js +36 -4
  379. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  380. package/dist/observability/monitored-cron.d.ts +29 -12
  381. package/dist/observability/monitored-cron.d.ts.map +1 -1
  382. package/dist/observability/monitored-cron.js +131 -46
  383. package/dist/observability/monitored-cron.js.map +1 -1
  384. package/dist/pairing/pairing.service.d.ts +6 -2
  385. package/dist/pairing/pairing.service.d.ts.map +1 -1
  386. package/dist/pdf/document/charts/chart-bar.d.ts +24 -0
  387. package/dist/pdf/document/charts/chart-bar.d.ts.map +1 -0
  388. package/dist/pdf/document/charts/chart-bar.js +117 -0
  389. package/dist/pdf/document/charts/chart-bar.js.map +1 -0
  390. package/dist/pdf/document/charts/chart-donut.d.ts +16 -0
  391. package/dist/pdf/document/charts/chart-donut.d.ts.map +1 -0
  392. package/dist/pdf/document/charts/chart-donut.js +89 -0
  393. package/dist/pdf/document/charts/chart-donut.js.map +1 -0
  394. package/dist/pdf/document/charts/chart-gauge.d.ts +15 -0
  395. package/dist/pdf/document/charts/chart-gauge.d.ts.map +1 -0
  396. package/dist/pdf/document/charts/chart-gauge.js +60 -0
  397. package/dist/pdf/document/charts/chart-gauge.js.map +1 -0
  398. package/dist/pdf/document/charts/chart-line.d.ts +29 -0
  399. package/dist/pdf/document/charts/chart-line.d.ts.map +1 -0
  400. package/dist/pdf/document/charts/chart-line.js +89 -0
  401. package/dist/pdf/document/charts/chart-line.js.map +1 -0
  402. package/dist/pdf/document/charts/chart-primitives.d.ts +64 -0
  403. package/dist/pdf/document/charts/chart-primitives.d.ts.map +1 -0
  404. package/dist/pdf/document/charts/chart-primitives.js +110 -0
  405. package/dist/pdf/document/charts/chart-primitives.js.map +1 -0
  406. package/dist/pdf/document/charts/chart-radar.d.ts +13 -0
  407. package/dist/pdf/document/charts/chart-radar.d.ts.map +1 -0
  408. package/dist/pdf/document/charts/chart-radar.js +83 -0
  409. package/dist/pdf/document/charts/chart-radar.js.map +1 -0
  410. package/dist/pdf/document/charts/chart-scale.d.ts +39 -0
  411. package/dist/pdf/document/charts/chart-scale.d.ts.map +1 -0
  412. package/dist/pdf/document/charts/chart-scale.js +118 -0
  413. package/dist/pdf/document/charts/chart-scale.js.map +1 -0
  414. package/dist/pdf/document/charts/index.d.ts +8 -0
  415. package/dist/pdf/document/charts/index.d.ts.map +1 -0
  416. package/dist/pdf/document/charts/index.js +24 -0
  417. package/dist/pdf/document/charts/index.js.map +1 -0
  418. package/dist/pdf/document/index.d.ts +8 -0
  419. package/dist/pdf/document/index.d.ts.map +1 -0
  420. package/dist/pdf/document/index.js +24 -0
  421. package/dist/pdf/document/index.js.map +1 -0
  422. package/dist/pdf/document/pdf-document.chrome.d.ts +20 -0
  423. package/dist/pdf/document/pdf-document.chrome.d.ts.map +1 -0
  424. package/dist/pdf/document/pdf-document.chrome.js +36 -0
  425. package/dist/pdf/document/pdf-document.chrome.js.map +1 -0
  426. package/dist/pdf/document/pdf-document.css.d.ts +20 -0
  427. package/dist/pdf/document/pdf-document.css.d.ts.map +1 -0
  428. package/dist/pdf/document/pdf-document.css.js +239 -0
  429. package/dist/pdf/document/pdf-document.css.js.map +1 -0
  430. package/dist/pdf/document/pdf-document.renderer.d.ts +10 -0
  431. package/dist/pdf/document/pdf-document.renderer.d.ts.map +1 -0
  432. package/dist/pdf/document/pdf-document.renderer.js +153 -0
  433. package/dist/pdf/document/pdf-document.renderer.js.map +1 -0
  434. package/dist/pdf/document/pdf-document.service.d.ts +27 -0
  435. package/dist/pdf/document/pdf-document.service.d.ts.map +1 -0
  436. package/dist/pdf/document/pdf-document.service.js +81 -0
  437. package/dist/pdf/document/pdf-document.service.js.map +1 -0
  438. package/dist/pdf/document/pdf-document.theme.d.ts +41 -0
  439. package/dist/pdf/document/pdf-document.theme.d.ts.map +1 -0
  440. package/dist/pdf/document/pdf-document.theme.js +105 -0
  441. package/dist/pdf/document/pdf-document.theme.js.map +1 -0
  442. package/dist/pdf/document/pdf-document.types.d.ts +108 -0
  443. package/dist/pdf/document/pdf-document.types.d.ts.map +1 -0
  444. package/dist/pdf/document/pdf-document.types.js +18 -0
  445. package/dist/pdf/document/pdf-document.types.js.map +1 -0
  446. package/dist/pdf/pdf.module.d.ts.map +1 -1
  447. package/dist/pdf/pdf.module.js +3 -2
  448. package/dist/pdf/pdf.module.js.map +1 -1
  449. package/dist/pdf/pdf.service.d.ts +69 -1
  450. package/dist/pdf/pdf.service.d.ts.map +1 -1
  451. package/dist/pdf/pdf.service.js +164 -63
  452. package/dist/pdf/pdf.service.js.map +1 -1
  453. package/dist/pdf/templates/commercial-proposal.template.d.ts +96 -0
  454. package/dist/pdf/templates/commercial-proposal.template.d.ts.map +1 -0
  455. package/dist/pdf/templates/commercial-proposal.template.js +276 -0
  456. package/dist/pdf/templates/commercial-proposal.template.js.map +1 -0
  457. package/dist/profile/dto/change-password.dto.d.ts.map +1 -1
  458. package/dist/profile/dto/change-password.dto.js +4 -6
  459. package/dist/profile/dto/change-password.dto.js.map +1 -1
  460. package/dist/profile/profile.controller.d.ts +1 -1
  461. package/dist/profile/profile.service.d.ts +1 -1
  462. package/dist/profile/profile.service.d.ts.map +1 -1
  463. package/dist/profile/profile.service.js +9 -3
  464. package/dist/profile/profile.service.js.map +1 -1
  465. package/dist/realtime/realtime-tick.coalescer.d.ts +34 -0
  466. package/dist/realtime/realtime-tick.coalescer.d.ts.map +1 -0
  467. package/dist/realtime/realtime-tick.coalescer.js +60 -0
  468. package/dist/realtime/realtime-tick.coalescer.js.map +1 -0
  469. package/dist/realtime/realtime.service.d.ts +2 -0
  470. package/dist/realtime/realtime.service.d.ts.map +1 -1
  471. package/dist/realtime/realtime.service.js +22 -2
  472. package/dist/realtime/realtime.service.js.map +1 -1
  473. package/dist/redis/redis-kv.service.d.ts +90 -0
  474. package/dist/redis/redis-kv.service.d.ts.map +1 -0
  475. package/dist/redis/redis-kv.service.js +247 -0
  476. package/dist/redis/redis-kv.service.js.map +1 -0
  477. package/dist/redis/redis-master.d.ts +29 -0
  478. package/dist/redis/redis-master.d.ts.map +1 -0
  479. package/dist/redis/redis-master.js +81 -0
  480. package/dist/redis/redis-master.js.map +1 -0
  481. package/dist/redis/redis-pubsub.d.ts +12 -0
  482. package/dist/redis/redis-pubsub.d.ts.map +1 -1
  483. package/dist/redis/redis-pubsub.js +25 -2
  484. package/dist/redis/redis-pubsub.js.map +1 -1
  485. package/dist/redis/redis.module.d.ts +11 -0
  486. package/dist/redis/redis.module.d.ts.map +1 -0
  487. package/dist/redis/redis.module.js +30 -0
  488. package/dist/redis/redis.module.js.map +1 -0
  489. package/dist/session/session.controller.d.ts +6 -2
  490. package/dist/session/session.controller.d.ts.map +1 -1
  491. package/dist/session/session.service.d.ts +118 -15
  492. package/dist/session/session.service.d.ts.map +1 -1
  493. package/dist/session/session.service.js +251 -77
  494. package/dist/session/session.service.js.map +1 -1
  495. package/dist/setting/favicon.controller.d.ts +26 -0
  496. package/dist/setting/favicon.controller.d.ts.map +1 -0
  497. package/dist/setting/favicon.controller.js +130 -0
  498. package/dist/setting/favicon.controller.js.map +1 -0
  499. package/dist/setting/setting.controller.d.ts +5 -0
  500. package/dist/setting/setting.controller.d.ts.map +1 -1
  501. package/dist/setting/setting.module.d.ts.map +1 -1
  502. package/dist/setting/setting.module.js +2 -1
  503. package/dist/setting/setting.module.js.map +1 -1
  504. package/dist/setting/setting.service.d.ts +7 -0
  505. package/dist/setting/setting.service.d.ts.map +1 -1
  506. package/dist/setting/setting.service.js +38 -3
  507. package/dist/setting/setting.service.js.map +1 -1
  508. package/dist/task/task.service.d.ts +17 -0
  509. package/dist/task/task.service.d.ts.map +1 -1
  510. package/dist/task/task.service.js +48 -13
  511. package/dist/task/task.service.js.map +1 -1
  512. package/dist/token/token.service.d.ts +19 -1
  513. package/dist/token/token.service.d.ts.map +1 -1
  514. package/dist/token/token.service.js +39 -2
  515. package/dist/token/token.service.js.map +1 -1
  516. package/dist/user/user-credential.util.d.ts +10 -0
  517. package/dist/user/user-credential.util.d.ts.map +1 -1
  518. package/dist/user/user-credential.util.js +14 -1
  519. package/dist/user/user-credential.util.js.map +1 -1
  520. package/dist/user/user.service.d.ts +12 -4
  521. package/dist/user/user.service.d.ts.map +1 -1
  522. package/dist/user/user.service.js +2 -11
  523. package/dist/user/user.service.js.map +1 -1
  524. package/dist/user/user.sort.d.ts +16 -0
  525. package/dist/user/user.sort.d.ts.map +1 -0
  526. package/dist/user/user.sort.js +25 -0
  527. package/dist/user/user.sort.js.map +1 -0
  528. package/dist/utils/abbreviate-name.d.ts +13 -0
  529. package/dist/utils/abbreviate-name.d.ts.map +1 -0
  530. package/dist/utils/abbreviate-name.js +42 -0
  531. package/dist/utils/abbreviate-name.js.map +1 -0
  532. package/dist/utils/date-range-query.dto.d.ts +11 -0
  533. package/dist/utils/date-range-query.dto.d.ts.map +1 -0
  534. package/dist/utils/date-range-query.dto.js +63 -0
  535. package/dist/utils/date-range-query.dto.js.map +1 -0
  536. package/dist/utils/date-range.d.ts +96 -0
  537. package/dist/utils/date-range.d.ts.map +1 -0
  538. package/dist/utils/date-range.js +172 -0
  539. package/dist/utils/date-range.js.map +1 -0
  540. package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
  541. package/dist/webhook-integration/webhook-utils.js +24 -0
  542. package/dist/webhook-integration/webhook-utils.js.map +1 -1
  543. package/dist/whatsapp-sender/whatsapp-recipients.d.ts +49 -0
  544. package/dist/whatsapp-sender/whatsapp-recipients.d.ts.map +1 -0
  545. package/dist/whatsapp-sender/whatsapp-recipients.js +66 -0
  546. package/dist/whatsapp-sender/whatsapp-recipients.js.map +1 -0
  547. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +25 -0
  548. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -1
  549. package/dist/whatsapp-sender/whatsapp-sender.service.js +71 -7
  550. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -1
  551. package/hedhog/data/integration_provider.yaml +9 -0
  552. package/hedhog/data/integration_type.yaml +12 -0
  553. package/hedhog/data/locale.yaml +0 -1
  554. package/hedhog/data/mail.yaml +2 -2
  555. package/hedhog/data/mail_layout.yaml +6 -3
  556. package/hedhog/data/menu.yaml +25 -5
  557. package/hedhog/data/route.yaml +148 -0
  558. package/hedhog/data/setting_group.yaml +189 -3
  559. package/hedhog/frontend/app/access-log/page.tsx.ejs +47 -53
  560. package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +33 -8
  561. package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +54 -13
  562. package/hedhog/frontend/app/account/components/mfa-method-card.tsx.ejs +7 -1
  563. package/hedhog/frontend/app/account/components/recovery-codes-dialog.tsx.ejs +1 -0
  564. package/hedhog/frontend/app/account/components/tokens.tsx.ejs +47 -17
  565. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +46 -5
  566. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +101 -30
  567. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +24 -8
  568. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +80 -15
  569. package/hedhog/frontend/app/configurations/[slug]/components/image-optimization-action.tsx.ejs +166 -0
  570. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +145 -45
  571. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +99 -219
  572. package/hedhog/frontend/app/configurations/[slug]/page.tsx.ejs +19 -1
  573. package/hedhog/frontend/app/configurations/layout.tsx.ejs +19 -5
  574. package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +2 -8
  575. package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +3 -0
  576. package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +4 -0
  577. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +43 -44
  578. package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +41 -3
  579. package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +42 -2
  580. package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +41 -3
  581. package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +39 -4
  582. package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +42 -3
  583. package/hedhog/frontend/app/incidents/page.tsx.ejs +60 -31
  584. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +45 -5
  585. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +92 -15
  586. package/hedhog/frontend/app/mail/log/page.tsx.ejs +109 -61
  587. package/hedhog/frontend/app/mail/template/page.tsx.ejs +125 -23
  588. package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +13 -15
  589. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +116 -110
  590. package/hedhog/frontend/app/message-templates/_components/message-template-sheet.tsx.ejs +245 -0
  591. package/hedhog/frontend/app/message-templates/_lib/types.ts.ejs +24 -0
  592. package/hedhog/frontend/app/message-templates/page.tsx.ejs +182 -0
  593. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1 -0
  594. package/hedhog/frontend/app/pages/page.tsx.ejs +94 -9
  595. package/hedhog/frontend/app/roles/menus.tsx.ejs +4 -4
  596. package/hedhog/frontend/app/roles/routes.tsx.ejs +4 -4
  597. package/hedhog/frontend/app/roles/users.tsx.ejs +4 -4
  598. package/hedhog/frontend/app/setting-list/page.tsx.ejs +71 -9
  599. package/hedhog/frontend/app/users/page.tsx.ejs +77 -67
  600. package/hedhog/frontend/messages/en.json +237 -37
  601. package/hedhog/frontend/messages/pt.json +237 -37
  602. package/hedhog/table/cron_lock.yaml +17 -0
  603. package/hedhog/table/file.yaml +13 -1
  604. package/hedhog/table/file_upload_chunk.yaml +23 -0
  605. package/hedhog/table/file_upload_ticket.yaml +67 -0
  606. package/hedhog/table/mcp_tool_call_log.yaml +30 -22
  607. package/hedhog/table/message_template.yaml +33 -0
  608. package/hedhog/table/setting.yaml +8 -0
  609. package/hedhog/table/user_session.yaml +36 -1
  610. package/package.json +5 -3
  611. package/src/ai/ai-agent.sort.ts +21 -0
  612. package/src/ai/ai-attachment.fragments.spec.ts +56 -3
  613. package/src/ai/ai.service.responses.spec.ts +429 -0
  614. package/src/ai/ai.service.spec.ts +173 -1
  615. package/src/ai/ai.service.ts +473 -220
  616. package/src/ai-instruction/ai-instruction.service.ts +32 -28
  617. package/src/ai-instruction/ai-instruction.sort.ts +32 -0
  618. package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +44 -0
  619. package/src/ai-instruction/ai-prompt-resolver.service.ts +29 -0
  620. package/src/auth/auth.module.ts +8 -1
  621. package/src/auth/auth.service.spec.ts +108 -1
  622. package/src/auth/auth.service.ts +59 -5
  623. package/src/auth/guards/auth.guard.ts +9 -1
  624. package/src/authorize/authorize.controller.ts +126 -11
  625. package/src/authorize/authorize.errors.ts +55 -0
  626. package/src/authorize/authorize.module.ts +6 -1
  627. package/src/authorize/authorize.service.spec.ts +379 -7
  628. package/src/authorize/authorize.service.ts +309 -23
  629. package/src/authorize/dto/authorize-info.dto.ts +21 -3
  630. package/src/authorize/dto/consent.dto.ts +21 -3
  631. package/src/authorize/dto/token.dto.ts +24 -2
  632. package/src/authorize/oauth-exception.filter.ts +58 -0
  633. package/src/authorize/oauth-metadata.service.ts +67 -0
  634. package/src/authorize/well-known.controller.spec.ts +84 -0
  635. package/src/authorize/well-known.controller.ts +96 -0
  636. package/src/captcha/captcha.service.spec.ts +211 -4
  637. package/src/captcha/captcha.service.ts +127 -10
  638. package/src/core.module.ts +9 -0
  639. package/src/dashboard/dashboard-component-role/dashboard-component-role.service.ts +2 -3
  640. package/src/dashboard/dashboard-component-role/dashboard-component-role.sort.ts +18 -0
  641. package/src/dashboard/dashboard-item/dashboard-item.service.ts +2 -3
  642. package/src/dashboard/dashboard-item/dashboard-item.sort.ts +19 -0
  643. package/src/dashboard/dashboard-role/dashboard-role.service.ts +2 -3
  644. package/src/dashboard/dashboard-role/dashboard-role.sort.ts +16 -0
  645. package/src/document-kit/document-kit.module.ts +12 -0
  646. package/src/document-kit/document-kit.registry.ts +125 -0
  647. package/src/document-kit/document-kit.service.spec.ts +156 -0
  648. package/src/document-kit/document-kit.service.ts +173 -0
  649. package/src/file/file-upload-ticket.service.spec.ts +422 -0
  650. package/src/file/file-upload-ticket.service.ts +513 -0
  651. package/src/file/file.controller.ts +65 -0
  652. package/src/file/file.module.ts +14 -2
  653. package/src/file/file.service.spec.ts +262 -1
  654. package/src/file/file.service.ts +505 -87
  655. package/src/file/filename-encoding.util.spec.ts +54 -0
  656. package/src/file/filename-encoding.util.ts +67 -0
  657. package/src/file/image-optimization.service.spec.ts +156 -19
  658. package/src/file/image-optimization.service.ts +106 -21
  659. package/src/file/mcp-file-source.schema.ts +86 -0
  660. package/src/file/mcp-file-source.service.spec.ts +473 -0
  661. package/src/file/mcp-file-source.service.ts +445 -0
  662. package/src/file/mimetype-sniff.util.spec.ts +126 -0
  663. package/src/file/mimetype-sniff.util.ts +265 -0
  664. package/src/file/remote-fetch.util.spec.ts +117 -0
  665. package/src/file/remote-fetch.util.ts +330 -0
  666. package/src/impersonation/dto/start-impersonation.dto.ts +5 -2
  667. package/src/impersonation/impersonation.service.spec.ts +24 -1
  668. package/src/impersonation/impersonation.service.ts +14 -4
  669. package/src/incident/incident.controller.ts +9 -1
  670. package/src/incident/incident.service.ts +7 -0
  671. package/src/index.ts +23 -1
  672. package/src/integration-profile/integration-profile.secrets.ts +28 -0
  673. package/src/integration-profile/integration-profile.service.ts +7 -64
  674. package/src/integration-profile/integration-profile.utils.spec.ts +9 -0
  675. package/src/integration-profile/integration-profile.utils.ts +5 -5
  676. package/src/integration-profile/testers/ai.testers.ts +70 -5
  677. package/src/integration-profile/testers/index.ts +2 -0
  678. package/src/integration-profile/testers/remaining.testers.spec.ts +144 -1
  679. package/src/integration-profile/testers/shipping.testers.ts +94 -0
  680. package/src/integration-profile/testers/tester-coverage.spec.ts +10 -0
  681. package/src/mail/dto/send.dto.ts +6 -1
  682. package/src/mail/mail-template.spec.ts +58 -1
  683. package/src/mail/mail.service.spec.ts +112 -0
  684. package/src/mail/mail.service.ts +42 -4
  685. package/src/mail-sent/mail-sent.service.ts +3 -0
  686. package/src/mail-sent/mail-sent.sort.ts +19 -0
  687. package/src/mcp/filters/mcp-challenge.filter.spec.ts +76 -0
  688. package/src/mcp/filters/mcp-challenge.filter.ts +70 -0
  689. package/src/mcp/guards/mcp-auth.guard.spec.ts +51 -2
  690. package/src/mcp/guards/mcp-auth.guard.ts +24 -1
  691. package/src/mcp/guards/mcp-permission.guard.spec.ts +109 -15
  692. package/src/mcp/guards/mcp-permission.guard.ts +76 -51
  693. package/src/mcp/mcp-audit.service.spec.ts +107 -0
  694. package/src/mcp/mcp-audit.service.ts +37 -1
  695. package/src/mcp/mcp-permission.service.spec.ts +197 -0
  696. package/src/mcp/mcp-permission.service.ts +184 -0
  697. package/src/mcp/mcp-server.service.spec.ts +84 -2
  698. package/src/mcp/mcp-server.service.ts +111 -87
  699. package/src/mcp/mcp.controller.ts +8 -1
  700. package/src/mcp/mcp.module.ts +7 -1
  701. package/src/mcp/tools/core-access-log.mcp-tools.ts +66 -0
  702. package/src/mcp/tools/core-ai.mcp-tools.ts +1 -1
  703. package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +1 -1
  704. package/src/mcp/tools/core-dashboard.mcp-tools.ts +1 -1
  705. package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +1 -2
  706. package/src/mcp/tools/core-files.mcp-tools.ts +202 -22
  707. package/src/mcp/tools/core-integration-events.mcp-tools.ts +1 -1
  708. package/src/mcp/tools/core-mail-sent.mcp-tools.ts +1 -1
  709. package/src/mcp/tools/core-mail.mcp-tools.ts +1 -1
  710. package/src/mcp/tools/core-menus.mcp-tools.ts +1 -2
  711. package/src/mcp/tools/core-notifications.mcp-tools.ts +0 -1
  712. package/src/mcp/tools/core-roles.mcp-tools.ts +1 -5
  713. package/src/mcp/tools/core-routes.mcp-tools.ts +1 -3
  714. package/src/mcp/tools/core-screens.mcp-tools.ts +1 -3
  715. package/src/mcp/tools/core-sessions.mcp-tools.ts +0 -2
  716. package/src/mcp/tools/core-settings.mcp-tools.ts +1 -2
  717. package/src/mcp/tools/core-users.mcp-tools.ts +1 -1
  718. package/src/mcp/tools/core-webhooks.mcp-tools.ts +1 -2
  719. package/src/mcp/types/mcp-context.type.ts +15 -6
  720. package/src/mcp-chat/mcp-chat.service.ts +8 -0
  721. package/src/meeting/meeting-provider.registry.ts +201 -0
  722. package/src/meeting/meeting.constants.ts +74 -0
  723. package/src/menu/menu.service.spec.ts +89 -0
  724. package/src/menu/menu.service.ts +29 -11
  725. package/src/message-template/dto/update-message-template.dto.ts +22 -0
  726. package/src/message-template/message-template-admin.service.spec.ts +163 -0
  727. package/src/message-template/message-template-admin.service.ts +239 -0
  728. package/src/message-template/message-template.controller.ts +52 -0
  729. package/src/message-template/message-template.module.ts +21 -0
  730. package/src/message-template/message-template.registry.spec.ts +62 -0
  731. package/src/message-template/message-template.registry.ts +125 -0
  732. package/src/message-template/message-template.service.spec.ts +149 -0
  733. package/src/message-template/message-template.service.ts +149 -0
  734. package/src/notification/notification.constants.ts +10 -0
  735. package/src/notification/notification.module.ts +3 -0
  736. package/src/notification/notification.service.spec.ts +75 -1
  737. package/src/notification/notification.service.ts +39 -1
  738. package/src/oauth/oauth-token-broker.service.spec.ts +108 -0
  739. package/src/oauth/oauth-token-broker.service.ts +129 -2
  740. package/src/oauth/oauth.controller.ts +0 -1
  741. package/src/oauth/oauth.errors.ts +7 -0
  742. package/src/oauth/oauth.module.ts +6 -1
  743. package/src/oauth/oauth.service.spec.ts +58 -7
  744. package/src/oauth/oauth.service.ts +71 -32
  745. package/src/oauth/providers/abstract.provider.spec.ts +192 -0
  746. package/src/oauth/providers/abstract.provider.ts +46 -14
  747. package/src/oauth/providers/github.provider.ts +57 -34
  748. package/src/oauth/providers/microsoft-entra-id.provider.spec.ts +133 -0
  749. package/src/oauth/providers/microsoft-entra-id.provider.ts +37 -3
  750. package/src/observability/monitored-cron.spec.ts +164 -31
  751. package/src/observability/monitored-cron.ts +154 -62
  752. package/src/pdf/document/charts/chart-bar.ts +217 -0
  753. package/src/pdf/document/charts/chart-donut.ts +163 -0
  754. package/src/pdf/document/charts/chart-gauge.ts +94 -0
  755. package/src/pdf/document/charts/chart-line.ts +159 -0
  756. package/src/pdf/document/charts/chart-primitives.ts +188 -0
  757. package/src/pdf/document/charts/chart-radar.ts +136 -0
  758. package/src/pdf/document/charts/chart-scale.spec.ts +93 -0
  759. package/src/pdf/document/charts/chart-scale.ts +141 -0
  760. package/src/pdf/document/charts/charts.spec.ts +157 -0
  761. package/src/pdf/document/charts/index.ts +7 -0
  762. package/src/pdf/document/index.ts +7 -0
  763. package/src/pdf/document/pdf-document.chrome.ts +38 -0
  764. package/src/pdf/document/pdf-document.css.ts +238 -0
  765. package/src/pdf/document/pdf-document.renderer.spec.ts +129 -0
  766. package/src/pdf/document/pdf-document.renderer.ts +215 -0
  767. package/src/pdf/document/pdf-document.service.ts +77 -0
  768. package/src/pdf/document/pdf-document.theme.ts +146 -0
  769. package/src/pdf/document/pdf-document.types.ts +97 -0
  770. package/src/pdf/pdf.module.ts +3 -2
  771. package/src/pdf/pdf.service.spec.ts +131 -0
  772. package/src/pdf/pdf.service.ts +245 -82
  773. package/src/pdf/templates/commercial-proposal.template.spec.ts +177 -0
  774. package/src/pdf/templates/commercial-proposal.template.ts +400 -0
  775. package/src/profile/dto/change-password.dto.ts +25 -7
  776. package/src/profile/profile.service.spec.ts +97 -0
  777. package/src/profile/profile.service.ts +9 -3
  778. package/src/realtime/realtime-tick.coalescer.spec.ts +92 -0
  779. package/src/realtime/realtime-tick.coalescer.ts +60 -0
  780. package/src/realtime/realtime.service.spec.ts +33 -0
  781. package/src/realtime/realtime.service.ts +28 -2
  782. package/src/redis/redis-kv.service.ts +261 -0
  783. package/src/redis/redis-master.spec.ts +111 -0
  784. package/src/redis/redis-master.ts +86 -0
  785. package/src/redis/redis-pubsub.ts +27 -3
  786. package/src/redis/redis.module.ts +17 -0
  787. package/src/session/session.service.spec.ts +121 -42
  788. package/src/session/session.service.ts +279 -82
  789. package/src/setting/favicon.controller.spec.ts +92 -0
  790. package/src/setting/favicon.controller.ts +135 -0
  791. package/src/setting/setting.module.ts +2 -1
  792. package/src/setting/setting.service.ts +44 -3
  793. package/src/task/task.service.spec.ts +41 -0
  794. package/src/task/task.service.ts +53 -13
  795. package/src/token/token.service.spec.ts +90 -0
  796. package/src/token/token.service.ts +48 -2
  797. package/src/user/user-credential.util.ts +14 -5
  798. package/src/user/user.service.ts +2 -12
  799. package/src/user/user.sort.ts +25 -0
  800. package/src/utils/abbreviate-name.spec.ts +50 -0
  801. package/src/utils/abbreviate-name.ts +44 -0
  802. package/src/utils/date-range-query.dto.ts +56 -0
  803. package/src/utils/date-range.spec.ts +175 -0
  804. package/src/utils/date-range.ts +246 -0
  805. package/src/webhook-integration/webhook-utils.spec.ts +67 -0
  806. package/src/webhook-integration/webhook-utils.ts +26 -0
  807. package/src/whatsapp-sender/whatsapp-recipients.spec.ts +89 -0
  808. package/src/whatsapp-sender/whatsapp-recipients.ts +83 -0
  809. package/src/whatsapp-sender/whatsapp-sender.service.spec.ts +185 -0
  810. package/src/whatsapp-sender/whatsapp-sender.service.ts +90 -7
  811. package/hedhog/query/device_pairing_request.sql +0 -46
  812. package/hedhog/query/impersonation_grant.sql +0 -71
  813. package/hedhog/query/oauth_authorize_pkce.sql +0 -58
  814. package/hedhog/query/oauth_mobile_state_token.sql +0 -30
  815. package/hedhog/query/oauth_web_ref_token.sql +0 -25
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  GetBucketNotificationConfigurationCommand,
3
+ GetObjectCommand,
3
4
  HeadBucketCommand,
4
5
  HeadObjectCommand,
5
6
  PutBucketNotificationConfigurationCommand,
6
7
  S3Client,
7
8
  } from '@aws-sdk/client-s3';
9
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
8
10
  import {
9
11
  AddPermissionCommand,
10
12
  CreateFunctionCommand,
@@ -23,14 +25,17 @@ import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
23
25
  import { PrismaService } from '@hed-hog/api-prisma';
24
26
  import {
25
27
  BadRequestException,
28
+ ForbiddenException,
26
29
  forwardRef,
27
30
  Inject,
28
31
  Injectable,
29
32
  Logger,
30
33
  NotFoundException,
31
- OnModuleInit
34
+ OnModuleInit,
35
+ ServiceUnavailableException
32
36
  } from '@nestjs/common';
33
37
  import { JwtService } from '@nestjs/jwt';
38
+ import { createHash } from 'crypto';
34
39
  import type { Request } from 'express';
35
40
  import { createWriteStream, promises as fs } from 'fs';
36
41
  import { tmpdir } from 'os';
@@ -44,6 +49,8 @@ import {
44
49
  } from '../integration-profile/integration-profile.utils';
45
50
  import { SettingService } from '../setting/setting.service';
46
51
  import { DeleteDTO } from './dto/delete.dto';
52
+ import { fixMojibake } from './filename-encoding.util';
53
+ import { MIMETYPE_SNIFF_BYTES } from './mimetype-sniff.util';
47
54
  import {
48
55
  ImageOptimizationService,
49
56
  ImageVariantFormat,
@@ -54,6 +61,9 @@ import {
54
61
  } from './provider/abstract.provider';
55
62
  import { ProviderFactory } from './provider/provider.factory';
56
63
 
64
+ /** Códigos de erro do S3/Spaces que indicam indisponibilidade passageira, não arquivo ruim. */
65
+ const STORAGE_UNAVAILABLE_CODES = ['SlowDown', 'ServiceUnavailable', 'InternalError', 'RequestTimeout'];
66
+
57
67
  type ResolvedProvider = {
58
68
  provider: AbstractProvider;
59
69
  providerId: number;
@@ -96,21 +106,13 @@ export class FileService implements OnModuleInit {
96
106
  return `${file.location}/${file.path}`;
97
107
  }
98
108
 
99
- private hasMojibake(value: string): boolean {
100
- return /Ã.|Â.|â[\u0080-\u00BF]/.test(value);
101
- }
102
-
109
+ /**
110
+ * Nome que chegou com o encoding trocado (busboy entrega `originalname` em
111
+ * latin1, e a base ainda recebe nome importado com o mesmo defeito). A lógica
112
+ * mora no util porque a migration de backfill a reproduz em plpgsql.
113
+ */
103
114
  private normalizeUploadedFilename(filename: string): string {
104
- if (!filename) {
105
- return filename;
106
- }
107
-
108
- if (!this.hasMojibake(filename)) {
109
- return filename;
110
- }
111
-
112
- const decoded = Buffer.from(filename, 'latin1').toString('utf8');
113
- return this.hasMojibake(decoded) ? filename : decoded;
115
+ return filename ? fixMojibake(filename) : filename;
114
116
  }
115
117
 
116
118
  constructor(
@@ -306,16 +308,37 @@ export class FileService implements OnModuleInit {
306
308
  return file;
307
309
  }
308
310
 
309
- private mapStorageNotFoundError(error: any, fileId: number) {
310
- const missingInStorage =
311
- error?.name === 'NoSuchKey' ||
312
- error?.Code === 'NoSuchKey' ||
313
- error?.$metadata?.httpStatusCode === 404;
311
+ /**
312
+ * Traduz a falha do provider de storage para a resposta HTTP certa.
313
+ *
314
+ * 5xx e throttle do S3/Spaces são indisponibilidade passageira, não defeito:
315
+ * viram 503 com `code: STORAGE_UNAVAILABLE`, que o HttpExceptionFilter da API
316
+ * responde com `Retry-After` e reporta deduplicado. Sem isso, um 503 do Spaces
317
+ * com corpo que não é XML (ex.: `upstream connect error` do balanceador)
318
+ * estourava no parse do SDK como `char 'u' is not expected` e virava 500.
319
+ *
320
+ * O status vem de `$metadata.httpStatusCode`, que o SDK carimba mesmo quando a
321
+ * desserialização do erro falha; `$response.statusCode` cobre o resto.
322
+ */
323
+ private mapStorageError(error: any, fileId: number): never {
324
+ const status = error?.$metadata?.httpStatusCode ?? error?.$response?.statusCode;
325
+ const codes = [error?.name, error?.Code];
314
326
 
315
- if (missingInStorage) {
327
+ if (codes.includes('NoSuchKey') || status === 404) {
316
328
  throw new NotFoundException(`File not found in storage: ${fileId}`);
317
329
  }
318
330
 
331
+ const unavailable =
332
+ (typeof status === 'number' && status >= 500) ||
333
+ codes.some((c) => STORAGE_UNAVAILABLE_CODES.includes(c));
334
+
335
+ if (unavailable) {
336
+ throw new ServiceUnavailableException(
337
+ { message: 'Storage temporarily unavailable', code: 'STORAGE_UNAVAILABLE' },
338
+ { cause: error },
339
+ );
340
+ }
341
+
319
342
  throw error;
320
343
  }
321
344
 
@@ -340,11 +363,15 @@ export class FileService implements OnModuleInit {
340
363
  const provider = await this.getProvider();
341
364
  const providerPath = this.resolveProviderPath(file);
342
365
 
366
+ // O HEAD só serve para descobrir o tamanho quando a tabela não o tem. Feito
367
+ // sempre, dobrava as requisições ao storage em cada segmento HLS.
343
368
  let metadata: any;
344
- try {
345
- metadata = await provider.metaData(providerPath);
346
- } catch {
347
- metadata = undefined;
369
+ if (file.size == null) {
370
+ try {
371
+ metadata = await provider.metaData(providerPath);
372
+ } catch {
373
+ metadata = undefined;
374
+ }
348
375
  }
349
376
 
350
377
  try {
@@ -355,7 +382,7 @@ export class FileService implements OnModuleInit {
355
382
  size: file.size ?? this.getFileSizeFromMetadata(metadata),
356
383
  };
357
384
  } catch (error) {
358
- this.mapStorageNotFoundError(error, fileId);
385
+ this.mapStorageError(error, fileId);
359
386
  }
360
387
  }
361
388
 
@@ -377,10 +404,15 @@ export class FileService implements OnModuleInit {
377
404
  const resolvedEnd = end !== undefined ? end : totalSize > 0 ? totalSize - 1 : undefined;
378
405
  const hasRange = start !== undefined;
379
406
 
380
- const stream = await provider.readStream(
381
- providerPath,
382
- hasRange ? { start: resolvedStart, end: resolvedEnd } : undefined,
383
- );
407
+ let stream: Awaited<ReturnType<AbstractProvider['readStream']>>;
408
+ try {
409
+ stream = await provider.readStream(
410
+ providerPath,
411
+ hasRange ? { start: resolvedStart, end: resolvedEnd } : undefined,
412
+ );
413
+ } catch (error) {
414
+ this.mapStorageError(error, fileId);
415
+ }
384
416
 
385
417
  const contentLength =
386
418
  resolvedEnd !== undefined ? resolvedEnd - resolvedStart + 1 : totalSize;
@@ -463,16 +495,7 @@ export class FileService implements OnModuleInit {
463
495
  try {
464
496
  providerBuffer = await provider.buffer(providerPath);
465
497
  } catch (error: any) {
466
- const missingInStorage =
467
- error?.name === 'NoSuchKey' ||
468
- error?.Code === 'NoSuchKey' ||
469
- error?.$metadata?.httpStatusCode === 404;
470
-
471
- if (missingInStorage) {
472
- throw new NotFoundException(`File not found in storage: ${fileId}`);
473
- }
474
-
475
- throw error;
498
+ this.mapStorageError(error, fileId);
476
499
  }
477
500
 
478
501
  const buffer = Buffer.from(providerBuffer);
@@ -548,6 +571,13 @@ export class FileService implements OnModuleInit {
548
571
  skipMimeValidation?: boolean;
549
572
  skipSizeValidation?: boolean;
550
573
  isPrivate?: boolean;
574
+ // Quem enviou. É o que permite recusar um `fileId` de outro usuário nas tools MCP
575
+ // (ver `assertFileUsable`); fica nulo nos caminhos internos sem usuário.
576
+ createdByUserId?: number | null;
577
+ // Grava a imagem byte a byte, sem a conversão para WebP nem o redimensionamento.
578
+ // Para quem entrega o arquivo a um consumidor externo que exige o formato
579
+ // original — o Instagram recusa WebP. O chamador já normalizou o arquivo.
580
+ skipImageOptimization?: boolean;
551
581
  },
552
582
  ) {
553
583
 
@@ -584,12 +614,18 @@ export class FileService implements OnModuleInit {
584
614
  fileBuffer.buffer,
585
615
  );
586
616
 
587
- const optimized = await this.imageOptimizationService.optimizeBuffer(
588
- fileBuffer.buffer,
589
- effectiveMimetype,
590
- normalizedFilename,
591
- { maxWidth: resize?.maxWidth, maxHeight: resize?.maxHeight },
592
- );
617
+ const optimized = options?.skipImageOptimization
618
+ ? {
619
+ buffer: fileBuffer.buffer,
620
+ mimetype: effectiveMimetype,
621
+ originalname: normalizedFilename,
622
+ }
623
+ : await this.imageOptimizationService.optimizeBuffer(
624
+ fileBuffer.buffer,
625
+ effectiveMimetype,
626
+ normalizedFilename,
627
+ { maxWidth: resize?.maxWidth, maxHeight: resize?.maxHeight },
628
+ );
593
629
 
594
630
  const normalizedFile = {
595
631
  ...fileBuffer,
@@ -610,6 +646,7 @@ export class FileService implements OnModuleInit {
610
646
  mimetype_id: await this.getMimeType(optimized.mimetype),
611
647
  size: optimized.buffer.length,
612
648
  is_private: options?.isPrivate ?? false,
649
+ created_by_user_id: options?.createdByUserId ?? null,
613
650
  },
614
651
  });
615
652
 
@@ -629,8 +666,12 @@ export class FileService implements OnModuleInit {
629
666
  skipSizeValidation?: boolean;
630
667
  // Tira o arquivo das rotas que servem por id sem autenticação.
631
668
  isPrivate?: boolean;
669
+ // Quem enviou. Ver a nota do mesmo campo em `upload`.
670
+ createdByUserId?: number | null;
632
671
  // Mesmo par maxWidth/maxHeight que `upload` aceita — só tem efeito em image/*.
633
672
  resize?: { maxWidth?: number; maxHeight?: number };
673
+ // Mesma opção de `upload`: a imagem segue o caminho de streaming, intacta.
674
+ skipImageOptimization?: boolean;
634
675
  },
635
676
  ) {
636
677
  if (!filePath) {
@@ -652,9 +693,18 @@ export class FileService implements OnModuleInit {
652
693
  );
653
694
  // Recupera o tipo real quando o caller não informou o mimetype (default antigo era
654
695
  // application/octet-stream, que fazia imagens caírem fora da otimização e do serve).
696
+ // Diferente de `upload`, aqui só existe um caminho no disco — e ler o arquivo inteiro
697
+ // é justamente o que o branch de streaming abaixo evita para SCORM/vídeo de vários GB.
698
+ // Por isso o sniffing recebe só o cabeçalho, e apenas quando o caller não declarou um
699
+ // tipo concreto: sem isso, uma imagem enviada como application/octet-stream sem
700
+ // extensão no nome escapava da otimização e era gravada byte a byte.
701
+ const declaredMimetype = metadata?.mimetype;
702
+ const isGenericMimetype =
703
+ !declaredMimetype || declaredMimetype === 'application/octet-stream';
655
704
  const mimetype = await this.resolveEffectiveMimetype(
656
- metadata?.mimetype,
705
+ declaredMimetype,
657
706
  originalname,
707
+ isGenericMimetype ? await this.readFileHeader(filePath) : undefined,
658
708
  );
659
709
 
660
710
  if (!metadata?.skipMimeValidation && !(await this.acceptMimetypes(mimetype))) {
@@ -671,8 +721,9 @@ export class FileService implements OnModuleInit {
671
721
  // streaming direto do disco via provider.uploadFromPath. Isso evita carregar
672
722
  // o arquivo inteiro na RAM (fs.readFile estoura o limite de Buffer / causa OOM)
673
723
  // e habilita upload multipart no S3. A otimização de imagem só se aplica a
674
- // image/*, então não há perda nesse caminho.
675
- if (!mimetype.startsWith('image/')) {
724
+ // image/*, então não há perda nesse caminho. `skipImageOptimization` manda a
725
+ // imagem pelo mesmo caminho: o chamador quer os bytes exatamente como estão.
726
+ if (!mimetype.startsWith('image/') || metadata?.skipImageOptimization) {
676
727
  const url = await provider.uploadFromPath(destination, filePath, {
677
728
  filename: originalname,
678
729
  mimetype,
@@ -687,6 +738,7 @@ export class FileService implements OnModuleInit {
687
738
  mimetype_id: await this.getMimeType(mimetype),
688
739
  size,
689
740
  is_private: metadata?.isPrivate ?? false,
741
+ created_by_user_id: metadata?.createdByUserId ?? null,
690
742
  },
691
743
  });
692
744
  }
@@ -724,20 +776,102 @@ export class FileService implements OnModuleInit {
724
776
  mimetype_id: await this.getMimeType(optimized.mimetype),
725
777
  size: optimized.buffer.length,
726
778
  is_private: metadata?.isPrivate ?? false,
779
+ created_by_user_id: metadata?.createdByUserId ?? null,
727
780
  },
728
781
  });
729
782
 
730
783
  return file;
731
784
  }
732
785
 
786
+ /**
787
+ * Mimetypes de imagem que `optimizeBuffer` devolve intactos por decisão de projeto
788
+ * (vetor não vira bitmap, GIF animado não vira quadro único). Enfileirá-los para
789
+ * reotimização seria custo de download e reprocessamento com resultado garantidamente
790
+ * nulo, então ficam fora da varredura.
791
+ */
792
+ private static readonly NON_OPTIMIZABLE_IMAGE_MIMETYPES = [
793
+ 'image/svg+xml',
794
+ 'image/gif',
795
+ ];
796
+
797
+ /**
798
+ * Lista as imagens armazenadas que valem uma passada por `reoptimizeFile`, para a
799
+ * operação em massa de reprocessamento do acervo.
800
+ *
801
+ * Devolve junto o total e a soma de bytes do filtro inteiro (não só da página), que é
802
+ * o que permite mostrar uma prévia antes de enfileirar dezenas de milhares de jobs.
803
+ * O core não conhece a fila — quem enfileira é a library `queue`, que depende deste
804
+ * pacote e não o contrário.
805
+ */
806
+ async findOptimizableImages(params?: {
807
+ /** Piso de tamanho em bytes; abaixo disso o ganho não paga o reprocessamento. */
808
+ minSize?: number;
809
+ /** Restringe a `location` exatas (ex.: `lms/xp/skills`), para rollout em ondas. */
810
+ locations?: string[];
811
+ offset?: number;
812
+ limit?: number;
813
+ }): Promise<{ ids: number[]; total: number; totalBytes: number }> {
814
+ const minSize = Math.max(0, Math.trunc(Number(params?.minSize) || 0));
815
+ const locations = (params?.locations ?? [])
816
+ .map((location) => String(location).trim())
817
+ .filter(Boolean);
818
+
819
+ const where: any = {
820
+ size: { gte: minSize },
821
+ file_mimetype: {
822
+ name: {
823
+ startsWith: 'image/',
824
+ notIn: FileService.NON_OPTIMIZABLE_IMAGE_MIMETYPES,
825
+ },
826
+ },
827
+ };
828
+
829
+ if (locations.length) {
830
+ where.location = { in: locations };
831
+ }
832
+
833
+ const [aggregate, rows] = await Promise.all([
834
+ this.prismaService.file.aggregate({
835
+ where,
836
+ _count: { _all: true },
837
+ _sum: { size: true },
838
+ }),
839
+ this.prismaService.file.findMany({
840
+ where,
841
+ select: { id: true },
842
+ // Ordem estável para que o enfileiramento paginado não pule nem repita linhas.
843
+ orderBy: { id: 'asc' },
844
+ skip: Math.max(0, Math.trunc(Number(params?.offset) || 0)),
845
+ take: Math.min(5000, Math.max(1, Math.trunc(Number(params?.limit) || 1000))),
846
+ }),
847
+ ]);
848
+
849
+ return {
850
+ ids: rows.map((row) => row.id),
851
+ total: aggregate._count._all ?? 0,
852
+ totalBytes: Number(aggregate._sum.size ?? 0),
853
+ };
854
+ }
855
+
856
+ /**
857
+ * Ganho mínimo para valer a regravação de um arquivo que já está no formato final.
858
+ *
859
+ * Recomprimir WebP sobre WebP sempre devolve alguns bytes a menos, então um limiar de
860
+ * "estritamente menor" nunca converge: cada passada da varredura trocaria o arquivo
861
+ * por um ganho irrisório e mais uma geração de perda de qualidade. Medido aqui, três
862
+ * passadas seguidas rendiam 10926 → 10664 → 10662 bytes — a última custou uma
863
+ * recompressão inteira para economizar 2 bytes.
864
+ */
865
+ private static readonly REOPTIMIZE_MIN_GAIN_RATIO = 0.1;
866
+
733
867
  /**
734
868
  * Re-applies the current image-optimization settings to an already-stored file,
735
869
  * rewriting it in place: the `file` record keeps the same id, so every row that
736
870
  * references it (course_image, course_lesson_video_frame, ...) stays valid without
737
- * any FK juggling. Only replaces the stored object when the optimized result is
738
- * strictly smaller or the mimetype changed (e.g. PNG → WebP) — this keeps the
739
- * operation idempotent and avoids repeated lossy recompression. Non-image files are
740
- * left untouched.
871
+ * any FK juggling. Only replaces the stored object when the mimetype changed
872
+ * (e.g. PNG → WebP) or the result is smaller by a margin that justifies the rewrite —
873
+ * that margin is what actually makes the operation idempotent and avoids repeated
874
+ * lossy recompression. Non-image files are left untouched.
741
875
  */
742
876
  async reoptimizeFile(fileId: number): Promise<{
743
877
  changed: boolean;
@@ -760,9 +894,15 @@ export class FileService implements OnModuleInit {
760
894
  );
761
895
 
762
896
  const mimetypeChanged = optimized.mimetype !== currentMimetype;
763
- const smaller = optimized.buffer.length < oldSize;
764
-
765
- if (!mimetypeChanged && !smaller) {
897
+ // Mudança de formato é o ganho principal (PNG → WebP) e vale por si; sem ela, só
898
+ // regrava quando a economia passa do limiar. `optimizeBuffer` já garante que o
899
+ // resultado nunca é maior que a entrada neste caminho (sem crop de alvo exato).
900
+ const worthRewriting =
901
+ oldSize > 0 &&
902
+ (oldSize - optimized.buffer.length) / oldSize >=
903
+ FileService.REOPTIMIZE_MIN_GAIN_RATIO;
904
+
905
+ if (!mimetypeChanged && !worthRewriting) {
766
906
  return {
767
907
  changed: false,
768
908
  oldSize,
@@ -850,7 +990,130 @@ export class FileService implements OnModuleInit {
850
990
  return files.map((file) => file.id);
851
991
  }
852
992
 
853
- async getFiles(paginationParams: PaginationDTO) {
993
+ /**
994
+ * `ownerUserId` restringe a listagem aos arquivos enviados por aquele usuário.
995
+ *
996
+ * Existe para as tools MCP: sem ele, `core.files.list` é um índice de tudo o que
997
+ * qualquer empresa já subiu, incluindo o que está gravado como `is_private`. O
998
+ * controller REST continua chamando sem o parâmetro, porque ali a rota já é `admin`
999
+ * e a tela de arquivos é justamente a visão global.
1000
+ */
1001
+ /**
1002
+ * Grava um stream em disco medindo, hasheando e guardando o cabeçalho de uma vez só.
1003
+ *
1004
+ * O upload assinado recebe o binário cru no corpo do PUT, e nada garante que venha com
1005
+ * `Content-Length` — sem o contador abaixo, um corpo aberto encheria o disco do pod. O
1006
+ * corte é feito em pleno voo, antes de o excedente chegar ao arquivo.
1007
+ *
1008
+ * Passa o cabeçalho adiante porque conferir o tipo real é obrigatório nesse caminho, e
1009
+ * reler o arquivo depois seria uma segunda passada por nada.
1010
+ */
1011
+ async writeStreamToPath(
1012
+ source: NodeJS.ReadableStream,
1013
+ targetPath: string,
1014
+ maxBytes: number,
1015
+ ): Promise<{ bytes: number; sha256: string; header: Buffer }> {
1016
+ const hash = createHash('sha256');
1017
+ const headerChunks: Buffer[] = [];
1018
+ let headerLength = 0;
1019
+ let bytes = 0;
1020
+
1021
+ const target = createWriteStream(targetPath);
1022
+
1023
+ await pipeline(
1024
+ source as any,
1025
+ async function* (chunks: AsyncIterable<Buffer>) {
1026
+ for await (const chunk of chunks) {
1027
+ const buffer = Buffer.from(chunk);
1028
+ bytes += buffer.length;
1029
+
1030
+ if (bytes > maxBytes) {
1031
+ throw new BadRequestException(
1032
+ `Upload exceeds the declared size of ${maxBytes} bytes`,
1033
+ );
1034
+ }
1035
+
1036
+ hash.update(buffer);
1037
+
1038
+ if (headerLength < MIMETYPE_SNIFF_BYTES) {
1039
+ const slice = buffer.subarray(0, MIMETYPE_SNIFF_BYTES - headerLength);
1040
+ headerChunks.push(slice);
1041
+ headerLength += slice.length;
1042
+ }
1043
+
1044
+ yield buffer;
1045
+ }
1046
+ },
1047
+ target,
1048
+ );
1049
+
1050
+ return {
1051
+ bytes,
1052
+ sha256: hash.digest('hex'),
1053
+ header: Buffer.concat(headerChunks),
1054
+ };
1055
+ }
1056
+
1057
+ /**
1058
+ * Conteúdo de um arquivo já armazenado, em memória.
1059
+ *
1060
+ * Existe para as tools que consomem os bytes sem persistir nada (importar extrato,
1061
+ * extrair dados de uma nota com IA): elas recebem um `fileId` e precisam do arquivo,
1062
+ * não de um stream. O teto evita que um `fileId` apontando para um SCORM de vários GB
1063
+ * derrube o pod — quem serve arquivo grande usa `openReadStream` e não passa por aqui.
1064
+ */
1065
+ async bufferById(fileId: number, maxBytes: number): Promise<Buffer> {
1066
+ const { stream } = await this.openReadStreamById(fileId);
1067
+ const chunks: Buffer[] = [];
1068
+ let total = 0;
1069
+
1070
+ for await (const chunk of stream as AsyncIterable<Buffer>) {
1071
+ total += chunk.length;
1072
+
1073
+ if (total > maxBytes) {
1074
+ (stream as any).destroy?.();
1075
+ throw new BadRequestException(
1076
+ `File ${fileId} is larger than the ${maxBytes} bytes this operation can load`,
1077
+ );
1078
+ }
1079
+
1080
+ chunks.push(Buffer.from(chunk));
1081
+ }
1082
+
1083
+ return Buffer.concat(chunks);
1084
+ }
1085
+
1086
+ /**
1087
+ * Nome do mimetype de um arquivo.
1088
+ *
1089
+ * `get()` e `upload()` devolvem a linha crua, sem a relação, e cada chamador que
1090
+ * precisava do tipo vinha refazendo o `include` por conta. Como o cache de
1091
+ * `getMimeType` é id-por-nome, este é o inverso dele e sai do mesmo mapa quando já
1092
+ * tiver sido consultado.
1093
+ */
1094
+ async mimetypeNameById(mimetypeId: number): Promise<string> {
1095
+ const cached = Object.entries(this.mimetypes).find(
1096
+ ([, id]) => id === mimetypeId,
1097
+ );
1098
+
1099
+ if (cached) {
1100
+ return cached[0];
1101
+ }
1102
+
1103
+ const row = await this.prismaService.file_mimetype.findUnique({
1104
+ where: { id: mimetypeId },
1105
+ select: { name: true },
1106
+ });
1107
+
1108
+ if (row?.name) {
1109
+ this.mimetypes[row.name] = mimetypeId;
1110
+ return row.name;
1111
+ }
1112
+
1113
+ return 'application/octet-stream';
1114
+ }
1115
+
1116
+ async getFiles(paginationParams: PaginationDTO, ownerUserId?: number) {
854
1117
  const fields = ['filename', 'path'];
855
1118
  const OR = this.prismaService.createInsensitiveSearch(
856
1119
  fields,
@@ -863,11 +1126,84 @@ export class FileService implements OnModuleInit {
863
1126
  {
864
1127
  where: {
865
1128
  OR,
1129
+ ...(ownerUserId ? { created_by_user_id: ownerUserId } : {}),
866
1130
  },
867
1131
  },
868
1132
  );
869
1133
  }
870
1134
 
1135
+ /**
1136
+ * Papéis que enxergam qualquer arquivo. Os mesmos que já governam as rotas de arquivo
1137
+ * em `route.yaml` — quem administra o acervo pela tela também o administra pelo MCP.
1138
+ */
1139
+ private static readonly FILE_ADMIN_ROLES = ['admin', 'admin-access'];
1140
+
1141
+ /** Cache curto de papéis, no mesmo espírito do McpPermissionService. */
1142
+ private readonly fileAdminCache = new Map<number, { value: boolean; at: number }>();
1143
+ private static readonly FILE_ADMIN_CACHE_TTL_MS = 30_000;
1144
+
1145
+ async isFileAdmin(userId: number): Promise<boolean> {
1146
+ const cached = this.fileAdminCache.get(userId);
1147
+
1148
+ if (cached && Date.now() - cached.at < FileService.FILE_ADMIN_CACHE_TTL_MS) {
1149
+ return cached.value;
1150
+ }
1151
+
1152
+ const found = await this.prismaService.role_user.findFirst({
1153
+ where: {
1154
+ user_id: userId,
1155
+ role: { slug: { in: FileService.FILE_ADMIN_ROLES } },
1156
+ },
1157
+ select: { role_id: true },
1158
+ });
1159
+
1160
+ const value = Boolean(found);
1161
+ this.fileAdminCache.set(userId, { value, at: Date.now() });
1162
+
1163
+ return value;
1164
+ }
1165
+
1166
+ /**
1167
+ * Porteiro do `fileId` vindo de fora: só o dono usa um arquivo, e quem administra o
1168
+ * acervo usa qualquer um.
1169
+ *
1170
+ * Sem isto, apontar um `fileId` numa tool seria enumerar — id de arquivo é sequencial,
1171
+ * exatamente o motivo pelo qual `is_private` existe. Arquivo anterior a esta coluna
1172
+ * (ou gravado por cron/seed/webhook) fica com dono nulo e só o admin alcança: não dá
1173
+ * para provar de quem ele é, e adivinhar a favor do chamador seria abrir a porta que
1174
+ * este método fecha.
1175
+ */
1176
+ async assertFileUsable(fileId: number, userId: number) {
1177
+ if (!Number.isInteger(fileId) || fileId <= 0) {
1178
+ throw new BadRequestException(`Invalid file id: ${fileId}`);
1179
+ }
1180
+
1181
+ const file = await this.prismaService.file.findUnique({
1182
+ where: { id: fileId },
1183
+ include: { file_mimetype: true },
1184
+ });
1185
+
1186
+ // Mesma resposta para inexistente e para alheio seria o ideal contra enumeração, mas
1187
+ // `get()` já responde 404 com o id, e divergir aqui só confundiria quem integra.
1188
+ if (!file) {
1189
+ throw new NotFoundException(`File not found: ${fileId}`);
1190
+ }
1191
+
1192
+ if (file.created_by_user_id === userId) {
1193
+ return file;
1194
+ }
1195
+
1196
+ if (await this.isFileAdmin(userId)) {
1197
+ return file;
1198
+ }
1199
+
1200
+ throw new ForbiddenException(
1201
+ file.created_by_user_id === null
1202
+ ? `File ${fileId} has no recorded owner and can only be used by an administrator`
1203
+ : `File ${fileId} belongs to another user`,
1204
+ );
1205
+ }
1206
+
871
1207
  async get(fileId: number) {
872
1208
  const file = await this.prismaService.file.findUnique({
873
1209
  where: { id: fileId },
@@ -1028,19 +1364,45 @@ export class FileService implements OnModuleInit {
1028
1364
  return undefined;
1029
1365
  }
1030
1366
 
1367
+ /**
1368
+ * Resolve o `file` cujo `resolveProviderPath` (location + path, ou path já combinado) bate com
1369
+ * o `filepath` embutido no token de download — é o inverso de `resolveProviderPath`.
1370
+ *
1371
+ * Bug corrigido (relatado como "Token de download inválido ou expirado" no storage local):
1372
+ * `tempURLById` assina o token com `resolveProviderPath(file)` (ex.:
1373
+ * "class-assignment-tasks/abc123.pdf", já com o prefixo de `location`), mas o upload local/S3
1374
+ * grava só o basename em `file.path` ("abc123.pdf") e o `location` separado em outra coluna.
1375
+ * Um `findFirst({ where: { path: filepath } })` direto nunca batia para esses arquivos — sempre
1376
+ * caía no `catch` abaixo e mostrava a mensagem genérica de token inválido, mesmo com o token
1377
+ * (e o arquivo) perfeitamente válidos. S3 mascarava isso porque `S3Provider.tempURL` devolve uma
1378
+ * URL assinada direto do bucket, sem passar por este método.
1379
+ */
1380
+ private async findFileByResolvedPath(filepath: string) {
1381
+ const bySameValue = await this.prismaService.file.findFirst({
1382
+ where: { path: filepath },
1383
+ include: { file_mimetype: true },
1384
+ });
1385
+ if (bySameValue) return bySameValue;
1386
+
1387
+ const slashIndex = filepath.lastIndexOf('/');
1388
+ if (slashIndex === -1) return null;
1389
+
1390
+ return this.prismaService.file.findFirst({
1391
+ where: {
1392
+ location: filepath.slice(0, slashIndex),
1393
+ path: filepath.slice(slashIndex + 1),
1394
+ },
1395
+ include: { file_mimetype: true },
1396
+ });
1397
+ }
1398
+
1031
1399
  async download(locale:string, token: string) {
1032
1400
  try {
1033
1401
  const { filepath } = this.jwtService.verify(token, {
1034
1402
  secret: process.env.JWT_SECRET,
1035
1403
  });
1036
1404
 
1037
- // Buscar o arquivo no banco para pegar nome original e mimetype
1038
- const file = await this.prismaService.file.findFirst({
1039
- where: { path: filepath },
1040
- include: {
1041
- file_mimetype: true,
1042
- },
1043
- });
1405
+ const file = await this.findFileByResolvedPath(filepath);
1044
1406
 
1045
1407
  if (!file) {
1046
1408
  throw new NotFoundException(getLocaleText('file.download.not_found', locale, `Not found: ${filepath}`));
@@ -1186,6 +1548,30 @@ export class FileService implements OnModuleInit {
1186
1548
  return map[ext] ?? null;
1187
1549
  }
1188
1550
 
1551
+ /**
1552
+ * Lê só o começo do arquivo, o bastante para o sharp reconhecer o formato pelo
1553
+ * cabeçalho. Existe para o sniffing de `uploadFromPath`, que não pode chamar
1554
+ * `fs.readFile`: o mesmo caminho recebe pacotes SCORM e vídeos de vários GB, e
1555
+ * carregá-los inteiros estoura o limite de Buffer. Devolve `undefined` em qualquer
1556
+ * falha de leitura — quem chama já trata a ausência do buffer.
1557
+ */
1558
+ private async readFileHeader(
1559
+ filePath: string,
1560
+ bytes = 64 * 1024,
1561
+ ): Promise<Buffer | undefined> {
1562
+ let handle: fs.FileHandle | undefined;
1563
+ try {
1564
+ handle = await fs.open(filePath, 'r');
1565
+ const buffer = Buffer.alloc(bytes);
1566
+ const { bytesRead } = await handle.read(buffer, 0, bytes, 0);
1567
+ return bytesRead > 0 ? buffer.subarray(0, bytesRead) : undefined;
1568
+ } catch {
1569
+ return undefined;
1570
+ } finally {
1571
+ await handle?.close().catch(() => undefined);
1572
+ }
1573
+ }
1574
+
1189
1575
  /**
1190
1576
  * Resolves the MIME type to persist for an upload. When the incoming mimetype is
1191
1577
  * generic (application/octet-stream or empty), recovers the real image type from
@@ -1197,29 +1583,7 @@ export class FileService implements OnModuleInit {
1197
1583
  name: string,
1198
1584
  buffer?: Buffer,
1199
1585
  ): Promise<string> {
1200
- if (mimetype && mimetype.startsWith('image/')) {
1201
- // O mimetype que chega do navegador vem da EXTENSÃO do arquivo, não do
1202
- // conteúdo: um PNG renomeado para `.svg` é anunciado como `image/svg+xml`.
1203
- // Gravar isso faz o endpoint de imagem servir bytes PNG sob Content-Type
1204
- // de SVG e, com o `nosniff` que a API envia, o navegador não corrige
1205
- // sozinho — a imagem simplesmente não renderiza, sem erro nenhum.
1206
- // Com os bytes em mãos, quem decide é a assinatura do arquivo.
1207
- if (buffer) {
1208
- const sniffed =
1209
- await this.imageOptimizationService.detectImageMimetype(buffer);
1210
- // Só sobrepõe quando o sniffing reconheceu o formato: um `null` significa
1211
- // que o sharp não entendeu o buffer, e aí o declarado ainda é o melhor
1212
- // palpite disponível.
1213
- if (sniffed && sniffed !== mimetype) {
1214
- this.logger.warn(
1215
- `Upload "${name}" foi anunciado como ${mimetype}, mas os bytes são ${sniffed}. Persistindo o tipo real.`,
1216
- );
1217
- return sniffed;
1218
- }
1219
- }
1220
-
1221
- return mimetype;
1222
- }
1586
+ if (mimetype && mimetype.startsWith('image/')) return mimetype;
1223
1587
  // Tipos concretos não-imagem (video, pdf, ...) são mantidos como estão.
1224
1588
  if (mimetype && mimetype !== 'application/octet-stream') return mimetype;
1225
1589
 
@@ -1514,6 +1878,17 @@ export class FileService implements OnModuleInit {
1514
1878
  return url;
1515
1879
  }
1516
1880
 
1881
+ /** Par de `tempURLById`, pela mesma razão: `path` cru resolve para NoSuchKey no S3. */
1882
+ async tempOpenURLById(fileId: number, expires = 3600) {
1883
+ const url = await this.tempURLById(fileId, expires);
1884
+
1885
+ if (typeof url === 'string') {
1886
+ return url.replace('/file/download/', '/file/open/');
1887
+ }
1888
+
1889
+ return url;
1890
+ }
1891
+
1517
1892
  async getTemporaryCredentials(params: {
1518
1893
  accessKeyId: string;
1519
1894
  secretAccessKey: string;
@@ -1596,6 +1971,49 @@ export class FileService implements OnModuleInit {
1596
1971
  };
1597
1972
  }
1598
1973
 
1974
+ /**
1975
+ * URL assinada de um objeto em bucket avulso.
1976
+ *
1977
+ * O `getFileUrl` do provider resolve arquivos do acervo, que vivem no destino
1978
+ * ativo do core. Este metodo serve para os buckets que outras libraries
1979
+ * configuram por conta propria — o Studio grava no perfil de armazenamento
1980
+ * dele, que pode nao ser o mesmo — e por isso recebe as credenciais e o bucket
1981
+ * de fora, como o `headS3Object` ao lado.
1982
+ */
1983
+ async signS3Object(params: {
1984
+ accessKeyId: string;
1985
+ secretAccessKey: string;
1986
+ sessionToken?: string;
1987
+ region: string;
1988
+ bucket: string;
1989
+ key: string;
1990
+ expiresInSeconds?: number;
1991
+ downloadFileName?: string;
1992
+ }): Promise<string> {
1993
+ const s3 = new S3Client({
1994
+ region: params.region,
1995
+ credentials: {
1996
+ accessKeyId: params.accessKeyId,
1997
+ secretAccessKey: params.secretAccessKey,
1998
+ ...(params.sessionToken ? { sessionToken: params.sessionToken } : {}),
1999
+ },
2000
+ });
2001
+
2002
+ const command = new GetObjectCommand({
2003
+ Bucket: params.bucket,
2004
+ Key: params.key,
2005
+ ...(params.downloadFileName
2006
+ ? {
2007
+ ResponseContentDisposition: `attachment; filename="${params.downloadFileName.replace(/"/g, '')}"`,
2008
+ }
2009
+ : {}),
2010
+ });
2011
+
2012
+ return getSignedUrl(s3 as any, command, {
2013
+ expiresIn: params.expiresInSeconds ?? 900,
2014
+ });
2015
+ }
2016
+
1599
2017
  async headS3Bucket(params: {
1600
2018
  accessKeyId: string;
1601
2019
  secretAccessKey: string;