@hed-hog/core 0.0.399 → 0.0.400

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 (668) 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 +4 -4
  6. package/dist/ai/ai.service.d.ts +35 -4
  7. package/dist/ai/ai.service.d.ts.map +1 -1
  8. package/dist/ai/ai.service.js +51 -137
  9. package/dist/ai/ai.service.js.map +1 -1
  10. package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
  11. package/dist/ai-instruction/ai-instruction.service.js +26 -23
  12. package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
  13. package/dist/ai-instruction/ai-instruction.sort.d.ts +16 -0
  14. package/dist/ai-instruction/ai-instruction.sort.d.ts.map +1 -0
  15. package/dist/ai-instruction/ai-instruction.sort.js +32 -0
  16. package/dist/ai-instruction/ai-instruction.sort.js.map +1 -0
  17. package/dist/auth/auth.controller.d.ts +24 -8
  18. package/dist/auth/auth.controller.d.ts.map +1 -1
  19. package/dist/auth/auth.module.d.ts.map +1 -1
  20. package/dist/auth/auth.module.js +8 -1
  21. package/dist/auth/auth.module.js.map +1 -1
  22. package/dist/auth/auth.service.d.ts +72 -25
  23. package/dist/auth/auth.service.d.ts.map +1 -1
  24. package/dist/auth/auth.service.js +41 -4
  25. package/dist/auth/auth.service.js.map +1 -1
  26. package/dist/auth/guards/auth.guard.d.ts +3 -1
  27. package/dist/auth/guards/auth.guard.d.ts.map +1 -1
  28. package/dist/auth/guards/auth.guard.js +12 -3
  29. package/dist/auth/guards/auth.guard.js.map +1 -1
  30. package/dist/authorize/authorize.controller.d.ts +29 -5
  31. package/dist/authorize/authorize.controller.d.ts.map +1 -1
  32. package/dist/authorize/authorize.controller.js +120 -13
  33. package/dist/authorize/authorize.controller.js.map +1 -1
  34. package/dist/authorize/authorize.errors.d.ts +34 -0
  35. package/dist/authorize/authorize.errors.d.ts.map +1 -0
  36. package/dist/authorize/authorize.errors.js +37 -0
  37. package/dist/authorize/authorize.errors.js.map +1 -0
  38. package/dist/authorize/authorize.module.d.ts.map +1 -1
  39. package/dist/authorize/authorize.module.js +6 -1
  40. package/dist/authorize/authorize.module.js.map +1 -1
  41. package/dist/authorize/authorize.service.d.ts +77 -3
  42. package/dist/authorize/authorize.service.d.ts.map +1 -1
  43. package/dist/authorize/authorize.service.js +212 -21
  44. package/dist/authorize/authorize.service.js.map +1 -1
  45. package/dist/authorize/dto/authorize-info.dto.d.ts +10 -1
  46. package/dist/authorize/dto/authorize-info.dto.d.ts.map +1 -1
  47. package/dist/authorize/dto/authorize-info.dto.js +16 -1
  48. package/dist/authorize/dto/authorize-info.dto.js.map +1 -1
  49. package/dist/authorize/dto/consent.dto.d.ts +10 -1
  50. package/dist/authorize/dto/consent.dto.d.ts.map +1 -1
  51. package/dist/authorize/dto/consent.dto.js +16 -1
  52. package/dist/authorize/dto/consent.dto.js.map +1 -1
  53. package/dist/authorize/dto/token.dto.d.ts +12 -0
  54. package/dist/authorize/dto/token.dto.d.ts.map +1 -1
  55. package/dist/authorize/dto/token.dto.js +21 -1
  56. package/dist/authorize/dto/token.dto.js.map +1 -1
  57. package/dist/authorize/oauth-exception.filter.d.ts +17 -0
  58. package/dist/authorize/oauth-exception.filter.d.ts.map +1 -0
  59. package/dist/authorize/oauth-exception.filter.js +54 -0
  60. package/dist/authorize/oauth-exception.filter.js.map +1 -0
  61. package/dist/authorize/oauth-metadata.service.d.ts +39 -0
  62. package/dist/authorize/oauth-metadata.service.d.ts.map +1 -0
  63. package/dist/authorize/oauth-metadata.service.js +81 -0
  64. package/dist/authorize/oauth-metadata.service.js.map +1 -0
  65. package/dist/authorize/well-known.controller.d.ts +67 -0
  66. package/dist/authorize/well-known.controller.d.ts.map +1 -0
  67. package/dist/authorize/well-known.controller.js +126 -0
  68. package/dist/authorize/well-known.controller.js.map +1 -0
  69. package/dist/captcha/captcha.service.d.ts +32 -2
  70. package/dist/captcha/captcha.service.d.ts.map +1 -1
  71. package/dist/captcha/captcha.service.js +85 -12
  72. package/dist/captcha/captcha.service.js.map +1 -1
  73. package/dist/challenge/challenge.service.d.ts +2 -2
  74. package/dist/core.module.d.ts.map +1 -1
  75. package/dist/core.module.js +6 -0
  76. package/dist/core.module.js.map +1 -1
  77. package/dist/dashboard/dashboard/dashboard.controller.d.ts +9 -9
  78. package/dist/dashboard/dashboard/dashboard.service.d.ts +9 -9
  79. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +3 -3
  80. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +3 -3
  81. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +3 -3
  82. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +3 -3
  83. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
  84. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js +2 -4
  85. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js.map +1 -1
  86. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts +8 -0
  87. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts.map +1 -0
  88. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js +18 -0
  89. package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js.map +1 -0
  90. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
  91. package/dist/dashboard/dashboard-item/dashboard-item.service.js +2 -4
  92. package/dist/dashboard/dashboard-item/dashboard-item.service.js.map +1 -1
  93. package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts +9 -0
  94. package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts.map +1 -0
  95. package/dist/dashboard/dashboard-item/dashboard-item.sort.js +19 -0
  96. package/dist/dashboard/dashboard-item/dashboard-item.sort.js.map +1 -0
  97. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +3 -3
  98. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +3 -3
  99. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
  100. package/dist/dashboard/dashboard-role/dashboard-role.service.js +2 -4
  101. package/dist/dashboard/dashboard-role/dashboard-role.service.js.map +1 -1
  102. package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts +8 -0
  103. package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts.map +1 -0
  104. package/dist/dashboard/dashboard-role/dashboard-role.sort.js +16 -0
  105. package/dist/dashboard/dashboard-role/dashboard-role.sort.js.map +1 -0
  106. package/dist/file/file-upload-ticket.service.d.ts +160 -0
  107. package/dist/file/file-upload-ticket.service.d.ts.map +1 -0
  108. package/dist/file/file-upload-ticket.service.js +382 -0
  109. package/dist/file/file-upload-ticket.service.js.map +1 -0
  110. package/dist/file/file.controller.d.ts +24 -1
  111. package/dist/file/file.controller.d.ts.map +1 -1
  112. package/dist/file/file.controller.js +63 -2
  113. package/dist/file/file.controller.js.map +1 -1
  114. package/dist/file/file.module.d.ts.map +1 -1
  115. package/dist/file/file.module.js +14 -2
  116. package/dist/file/file.module.js.map +1 -1
  117. package/dist/file/file.service.d.ts +182 -6
  118. package/dist/file/file.service.d.ts.map +1 -1
  119. package/dist/file/file.service.js +386 -54
  120. package/dist/file/file.service.js.map +1 -1
  121. package/dist/file/filename-encoding.util.d.ts +24 -0
  122. package/dist/file/filename-encoding.util.d.ts.map +1 -0
  123. package/dist/file/filename-encoding.util.js +63 -0
  124. package/dist/file/filename-encoding.util.js.map +1 -0
  125. package/dist/file/image-optimization.service.d.ts +27 -0
  126. package/dist/file/image-optimization.service.d.ts.map +1 -1
  127. package/dist/file/image-optimization.service.js +63 -14
  128. package/dist/file/image-optimization.service.js.map +1 -1
  129. package/dist/file/mcp-file-source.schema.d.ts +33 -0
  130. package/dist/file/mcp-file-source.schema.d.ts.map +1 -0
  131. package/dist/file/mcp-file-source.schema.js +75 -0
  132. package/dist/file/mcp-file-source.schema.js.map +1 -0
  133. package/dist/file/mcp-file-source.service.d.ts +124 -0
  134. package/dist/file/mcp-file-source.service.d.ts.map +1 -0
  135. package/dist/file/mcp-file-source.service.js +262 -0
  136. package/dist/file/mcp-file-source.service.js.map +1 -0
  137. package/dist/file/mimetype-sniff.util.d.ts +62 -0
  138. package/dist/file/mimetype-sniff.util.d.ts.map +1 -0
  139. package/dist/file/mimetype-sniff.util.js +226 -0
  140. package/dist/file/mimetype-sniff.util.js.map +1 -0
  141. package/dist/file/remote-fetch.util.d.ts +35 -0
  142. package/dist/file/remote-fetch.util.d.ts.map +1 -0
  143. package/dist/file/remote-fetch.util.js +236 -0
  144. package/dist/file/remote-fetch.util.js.map +1 -0
  145. package/dist/impersonation/dto/start-impersonation.dto.d.ts +4 -1
  146. package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -1
  147. package/dist/impersonation/dto/start-impersonation.dto.js +1 -1
  148. package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -1
  149. package/dist/impersonation/impersonation.service.d.ts +8 -3
  150. package/dist/impersonation/impersonation.service.d.ts.map +1 -1
  151. package/dist/impersonation/impersonation.service.js +14 -4
  152. package/dist/impersonation/impersonation.service.js.map +1 -1
  153. package/dist/incident/incident.controller.d.ts +2 -1
  154. package/dist/incident/incident.controller.d.ts.map +1 -1
  155. package/dist/incident/incident.controller.js +10 -6
  156. package/dist/incident/incident.controller.js.map +1 -1
  157. package/dist/incident/incident.service.d.ts +2 -0
  158. package/dist/incident/incident.service.d.ts.map +1 -1
  159. package/dist/incident/incident.service.js +4 -0
  160. package/dist/incident/incident.service.js.map +1 -1
  161. package/dist/index.d.ts +17 -0
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +17 -0
  164. package/dist/index.js.map +1 -1
  165. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  166. package/dist/integration-profile/integration-profile.secrets.js +7 -0
  167. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  168. package/dist/integration-profile/integration-profile.service.d.ts +0 -13
  169. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  170. package/dist/integration-profile/integration-profile.service.js +5 -40
  171. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  172. package/dist/integration-profile/integration-profile.utils.js +5 -5
  173. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  174. package/dist/integration-profile/testers/index.d.ts.map +1 -1
  175. package/dist/integration-profile/testers/index.js +2 -0
  176. package/dist/integration-profile/testers/index.js.map +1 -1
  177. package/dist/integration-profile/testers/shipping.testers.d.ts +3 -0
  178. package/dist/integration-profile/testers/shipping.testers.d.ts.map +1 -0
  179. package/dist/integration-profile/testers/shipping.testers.js +71 -0
  180. package/dist/integration-profile/testers/shipping.testers.js.map +1 -0
  181. package/dist/locale/locale.controller.d.ts +1 -1
  182. package/dist/locale/locale.service.d.ts +1 -1
  183. package/dist/mail/dto/send.dto.d.ts +6 -1
  184. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  185. package/dist/mail/dto/send.dto.js.map +1 -1
  186. package/dist/mail/mail.service.d.ts +9 -0
  187. package/dist/mail/mail.service.d.ts.map +1 -1
  188. package/dist/mail/mail.service.js +34 -14
  189. package/dist/mail/mail.service.js.map +1 -1
  190. package/dist/mail-sent/mail-sent.controller.d.ts +1 -1
  191. package/dist/mail-sent/mail-sent.service.d.ts +1 -1
  192. package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
  193. package/dist/mail-sent/mail-sent.service.js +2 -1
  194. package/dist/mail-sent/mail-sent.service.js.map +1 -1
  195. package/dist/mail-sent/mail-sent.sort.d.ts +9 -0
  196. package/dist/mail-sent/mail-sent.sort.d.ts.map +1 -0
  197. package/dist/mail-sent/mail-sent.sort.js +19 -0
  198. package/dist/mail-sent/mail-sent.sort.js.map +1 -0
  199. package/dist/mcp/filters/mcp-challenge.filter.d.ts +20 -0
  200. package/dist/mcp/filters/mcp-challenge.filter.d.ts.map +1 -0
  201. package/dist/mcp/filters/mcp-challenge.filter.js +69 -0
  202. package/dist/mcp/filters/mcp-challenge.filter.js.map +1 -0
  203. package/dist/mcp/guards/mcp-auth.guard.d.ts +4 -1
  204. package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
  205. package/dist/mcp/guards/mcp-auth.guard.js +19 -5
  206. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
  207. package/dist/mcp/guards/mcp-permission.guard.d.ts +25 -3
  208. package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -1
  209. package/dist/mcp/guards/mcp-permission.guard.js +46 -26
  210. package/dist/mcp/guards/mcp-permission.guard.js.map +1 -1
  211. package/dist/mcp/mcp-audit.service.d.ts +17 -0
  212. package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
  213. package/dist/mcp/mcp-audit.service.js +32 -3
  214. package/dist/mcp/mcp-audit.service.js.map +1 -1
  215. package/dist/mcp/mcp-permission.service.d.ts +64 -0
  216. package/dist/mcp/mcp-permission.service.d.ts.map +1 -0
  217. package/dist/mcp/mcp-permission.service.js +178 -0
  218. package/dist/mcp/mcp-permission.service.js.map +1 -0
  219. package/dist/mcp/mcp-server.service.d.ts +3 -1
  220. package/dist/mcp/mcp-server.service.d.ts.map +1 -1
  221. package/dist/mcp/mcp-server.service.js +36 -15
  222. package/dist/mcp/mcp-server.service.js.map +1 -1
  223. package/dist/mcp/mcp.controller.d.ts.map +1 -1
  224. package/dist/mcp/mcp.controller.js +10 -2
  225. package/dist/mcp/mcp.controller.js.map +1 -1
  226. package/dist/mcp/mcp.module.d.ts.map +1 -1
  227. package/dist/mcp/mcp.module.js +5 -1
  228. package/dist/mcp/mcp.module.js.map +1 -1
  229. package/dist/mcp/tools/core-ai.mcp-tools.js +2 -9
  230. package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -1
  231. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +1 -1
  232. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -1
  233. package/dist/mcp/tools/core-dashboard.mcp-tools.js +2 -9
  234. package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -1
  235. package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -1
  236. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +2 -10
  237. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -1
  238. package/dist/mcp/tools/core-files.mcp-tools.d.ts +17 -5
  239. package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -1
  240. package/dist/mcp/tools/core-files.mcp-tools.js +186 -24
  241. package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -1
  242. package/dist/mcp/tools/core-integration-events.mcp-tools.js +2 -9
  243. package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -1
  244. package/dist/mcp/tools/core-mail-sent.mcp-tools.js +2 -14
  245. package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -1
  246. package/dist/mcp/tools/core-mail.mcp-tools.js +2 -9
  247. package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -1
  248. package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -1
  249. package/dist/mcp/tools/core-menus.mcp-tools.js +2 -10
  250. package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -1
  251. package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -1
  252. package/dist/mcp/tools/core-notifications.mcp-tools.js +0 -1
  253. package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -1
  254. package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -1
  255. package/dist/mcp/tools/core-roles.mcp-tools.js +2 -13
  256. package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -1
  257. package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -1
  258. package/dist/mcp/tools/core-routes.mcp-tools.js +2 -11
  259. package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -1
  260. package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -1
  261. package/dist/mcp/tools/core-screens.mcp-tools.js +2 -11
  262. package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -1
  263. package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -1
  264. package/dist/mcp/tools/core-sessions.mcp-tools.js +0 -2
  265. package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -1
  266. package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
  267. package/dist/mcp/tools/core-settings.mcp-tools.js +2 -10
  268. package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
  269. package/dist/mcp/tools/core-users.mcp-tools.js +2 -9
  270. package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -1
  271. package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -1
  272. package/dist/mcp/tools/core-webhooks.mcp-tools.js +2 -10
  273. package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -1
  274. package/dist/mcp/types/mcp-context.type.d.ts +9 -0
  275. package/dist/mcp/types/mcp-context.type.d.ts.map +1 -1
  276. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  277. package/dist/mcp-chat/mcp-chat.service.js +8 -0
  278. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  279. package/dist/meeting/meeting-provider.registry.d.ts +115 -0
  280. package/dist/meeting/meeting-provider.registry.d.ts.map +1 -1
  281. package/dist/meeting/meeting-provider.registry.js.map +1 -1
  282. package/dist/meeting/meeting.constants.d.ts +70 -0
  283. package/dist/meeting/meeting.constants.d.ts.map +1 -1
  284. package/dist/meeting/meeting.constants.js +9 -1
  285. package/dist/meeting/meeting.constants.js.map +1 -1
  286. package/dist/menu/menu.service.d.ts.map +1 -1
  287. package/dist/menu/menu.service.js +29 -9
  288. package/dist/menu/menu.service.js.map +1 -1
  289. package/dist/message-template/dto/update-message-template.dto.d.ts +18 -0
  290. package/dist/message-template/dto/update-message-template.dto.d.ts.map +1 -0
  291. package/dist/message-template/dto/update-message-template.dto.js +38 -0
  292. package/dist/message-template/dto/update-message-template.dto.js.map +1 -0
  293. package/dist/message-template/message-template-admin.service.d.ts +70 -0
  294. package/dist/message-template/message-template-admin.service.d.ts.map +1 -0
  295. package/dist/message-template/message-template-admin.service.js +226 -0
  296. package/dist/message-template/message-template-admin.service.js.map +1 -0
  297. package/dist/message-template/message-template.controller.d.ts +29 -0
  298. package/dist/message-template/message-template.controller.d.ts.map +1 -0
  299. package/dist/message-template/message-template.controller.js +101 -0
  300. package/dist/message-template/message-template.controller.js.map +1 -0
  301. package/dist/message-template/message-template.module.d.ts +10 -0
  302. package/dist/message-template/message-template.module.d.ts.map +1 -0
  303. package/dist/message-template/message-template.module.js +33 -0
  304. package/dist/message-template/message-template.module.js.map +1 -0
  305. package/dist/message-template/message-template.registry.d.ts +55 -0
  306. package/dist/message-template/message-template.registry.d.ts.map +1 -0
  307. package/dist/message-template/message-template.registry.js +64 -0
  308. package/dist/message-template/message-template.registry.js.map +1 -0
  309. package/dist/message-template/message-template.service.d.ts +59 -0
  310. package/dist/message-template/message-template.service.d.ts.map +1 -0
  311. package/dist/message-template/message-template.service.js +166 -0
  312. package/dist/message-template/message-template.service.js.map +1 -0
  313. package/dist/notification/notification.constants.d.ts +11 -0
  314. package/dist/notification/notification.constants.d.ts.map +1 -0
  315. package/dist/notification/notification.constants.js +14 -0
  316. package/dist/notification/notification.constants.js.map +1 -0
  317. package/dist/notification/notification.controller.d.ts +20 -20
  318. package/dist/notification/notification.module.d.ts.map +1 -1
  319. package/dist/notification/notification.module.js +3 -0
  320. package/dist/notification/notification.module.js.map +1 -1
  321. package/dist/notification/notification.service.d.ts +33 -21
  322. package/dist/notification/notification.service.d.ts.map +1 -1
  323. package/dist/notification/notification.service.js +36 -2
  324. package/dist/notification/notification.service.js.map +1 -1
  325. package/dist/oauth/oauth.controller.d.ts +4 -6
  326. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  327. package/dist/oauth/oauth.controller.js +0 -1
  328. package/dist/oauth/oauth.controller.js.map +1 -1
  329. package/dist/oauth/oauth.errors.d.ts +15 -1
  330. package/dist/oauth/oauth.errors.d.ts.map +1 -1
  331. package/dist/oauth/oauth.errors.js +9 -1
  332. package/dist/oauth/oauth.errors.js.map +1 -1
  333. package/dist/oauth/oauth.module.d.ts.map +1 -1
  334. package/dist/oauth/oauth.module.js +6 -1
  335. package/dist/oauth/oauth.module.js.map +1 -1
  336. package/dist/oauth/oauth.service.d.ts +25 -5
  337. package/dist/oauth/oauth.service.d.ts.map +1 -1
  338. package/dist/oauth/oauth.service.js +63 -27
  339. package/dist/oauth/oauth.service.js.map +1 -1
  340. package/dist/oauth/providers/abstract.provider.d.ts +10 -0
  341. package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
  342. package/dist/oauth/providers/abstract.provider.js +39 -12
  343. package/dist/oauth/providers/abstract.provider.js.map +1 -1
  344. package/dist/oauth/providers/github.provider.d.ts +1 -1
  345. package/dist/oauth/providers/github.provider.d.ts.map +1 -1
  346. package/dist/oauth/providers/github.provider.js +48 -22
  347. package/dist/oauth/providers/github.provider.js.map +1 -1
  348. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  349. package/dist/oauth/providers/microsoft-entra-id.provider.js +6 -0
  350. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  351. package/dist/observability/monitored-cron.d.ts +29 -12
  352. package/dist/observability/monitored-cron.d.ts.map +1 -1
  353. package/dist/observability/monitored-cron.js +131 -46
  354. package/dist/observability/monitored-cron.js.map +1 -1
  355. package/dist/pairing/pairing.service.d.ts +6 -2
  356. package/dist/pairing/pairing.service.d.ts.map +1 -1
  357. package/dist/profile/dto/change-password.dto.d.ts.map +1 -1
  358. package/dist/profile/dto/change-password.dto.js +4 -6
  359. package/dist/profile/dto/change-password.dto.js.map +1 -1
  360. package/dist/profile/profile.controller.d.ts +1 -1
  361. package/dist/profile/profile.service.d.ts +1 -1
  362. package/dist/profile/profile.service.d.ts.map +1 -1
  363. package/dist/profile/profile.service.js +9 -3
  364. package/dist/profile/profile.service.js.map +1 -1
  365. package/dist/realtime/realtime-tick.coalescer.d.ts +34 -0
  366. package/dist/realtime/realtime-tick.coalescer.d.ts.map +1 -0
  367. package/dist/realtime/realtime-tick.coalescer.js +60 -0
  368. package/dist/realtime/realtime-tick.coalescer.js.map +1 -0
  369. package/dist/realtime/realtime.service.d.ts +2 -0
  370. package/dist/realtime/realtime.service.d.ts.map +1 -1
  371. package/dist/realtime/realtime.service.js +22 -2
  372. package/dist/realtime/realtime.service.js.map +1 -1
  373. package/dist/redis/redis-kv.service.d.ts +90 -0
  374. package/dist/redis/redis-kv.service.d.ts.map +1 -0
  375. package/dist/redis/redis-kv.service.js +247 -0
  376. package/dist/redis/redis-kv.service.js.map +1 -0
  377. package/dist/redis/redis-master.d.ts +29 -0
  378. package/dist/redis/redis-master.d.ts.map +1 -0
  379. package/dist/redis/redis-master.js +81 -0
  380. package/dist/redis/redis-master.js.map +1 -0
  381. package/dist/redis/redis-pubsub.d.ts +12 -0
  382. package/dist/redis/redis-pubsub.d.ts.map +1 -1
  383. package/dist/redis/redis-pubsub.js +25 -2
  384. package/dist/redis/redis-pubsub.js.map +1 -1
  385. package/dist/redis/redis.module.d.ts +11 -0
  386. package/dist/redis/redis.module.d.ts.map +1 -0
  387. package/dist/redis/redis.module.js +30 -0
  388. package/dist/redis/redis.module.js.map +1 -0
  389. package/dist/session/session.controller.d.ts +6 -2
  390. package/dist/session/session.controller.d.ts.map +1 -1
  391. package/dist/session/session.service.d.ts +118 -15
  392. package/dist/session/session.service.d.ts.map +1 -1
  393. package/dist/session/session.service.js +251 -77
  394. package/dist/session/session.service.js.map +1 -1
  395. package/dist/setting/setting.controller.d.ts +5 -0
  396. package/dist/setting/setting.controller.d.ts.map +1 -1
  397. package/dist/setting/setting.service.d.ts +7 -0
  398. package/dist/setting/setting.service.d.ts.map +1 -1
  399. package/dist/setting/setting.service.js +38 -3
  400. package/dist/setting/setting.service.js.map +1 -1
  401. package/dist/task/task.service.d.ts +17 -0
  402. package/dist/task/task.service.d.ts.map +1 -1
  403. package/dist/task/task.service.js +48 -13
  404. package/dist/task/task.service.js.map +1 -1
  405. package/dist/token/token.service.d.ts +19 -1
  406. package/dist/token/token.service.d.ts.map +1 -1
  407. package/dist/token/token.service.js +39 -2
  408. package/dist/token/token.service.js.map +1 -1
  409. package/dist/user/user-credential.util.d.ts +10 -0
  410. package/dist/user/user-credential.util.d.ts.map +1 -1
  411. package/dist/user/user-credential.util.js +14 -1
  412. package/dist/user/user-credential.util.js.map +1 -1
  413. package/dist/user/user.service.d.ts +12 -4
  414. package/dist/user/user.service.d.ts.map +1 -1
  415. package/dist/user/user.service.js +2 -11
  416. package/dist/user/user.service.js.map +1 -1
  417. package/dist/user/user.sort.d.ts +16 -0
  418. package/dist/user/user.sort.d.ts.map +1 -0
  419. package/dist/user/user.sort.js +25 -0
  420. package/dist/user/user.sort.js.map +1 -0
  421. package/dist/utils/abbreviate-name.d.ts +13 -0
  422. package/dist/utils/abbreviate-name.d.ts.map +1 -0
  423. package/dist/utils/abbreviate-name.js +42 -0
  424. package/dist/utils/abbreviate-name.js.map +1 -0
  425. package/dist/utils/date-range-query.dto.d.ts +11 -0
  426. package/dist/utils/date-range-query.dto.d.ts.map +1 -0
  427. package/dist/utils/date-range-query.dto.js +63 -0
  428. package/dist/utils/date-range-query.dto.js.map +1 -0
  429. package/dist/utils/date-range.d.ts +96 -0
  430. package/dist/utils/date-range.d.ts.map +1 -0
  431. package/dist/utils/date-range.js +172 -0
  432. package/dist/utils/date-range.js.map +1 -0
  433. package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
  434. package/dist/webhook-integration/webhook-utils.js +24 -0
  435. package/dist/webhook-integration/webhook-utils.js.map +1 -1
  436. package/dist/whatsapp-sender/whatsapp-recipients.d.ts +49 -0
  437. package/dist/whatsapp-sender/whatsapp-recipients.d.ts.map +1 -0
  438. package/dist/whatsapp-sender/whatsapp-recipients.js +66 -0
  439. package/dist/whatsapp-sender/whatsapp-recipients.js.map +1 -0
  440. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +25 -0
  441. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -1
  442. package/dist/whatsapp-sender/whatsapp-sender.service.js +46 -5
  443. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -1
  444. package/hedhog/data/integration_provider.yaml +9 -0
  445. package/hedhog/data/integration_type.yaml +6 -0
  446. package/hedhog/data/locale.yaml +0 -1
  447. package/hedhog/data/mail.yaml +2 -2
  448. package/hedhog/data/mail_layout.yaml +6 -3
  449. package/hedhog/data/menu.yaml +25 -5
  450. package/hedhog/data/route.yaml +140 -0
  451. package/hedhog/data/setting_group.yaml +137 -3
  452. package/hedhog/frontend/app/access-log/page.tsx.ejs +47 -53
  453. package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +33 -8
  454. package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +54 -13
  455. package/hedhog/frontend/app/account/components/mfa-method-card.tsx.ejs +7 -1
  456. package/hedhog/frontend/app/account/components/recovery-codes-dialog.tsx.ejs +1 -0
  457. package/hedhog/frontend/app/account/components/tokens.tsx.ejs +47 -17
  458. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +46 -5
  459. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +101 -30
  460. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +24 -8
  461. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +80 -15
  462. package/hedhog/frontend/app/configurations/[slug]/components/image-optimization-action.tsx.ejs +166 -0
  463. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +145 -45
  464. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +99 -219
  465. package/hedhog/frontend/app/configurations/[slug]/page.tsx.ejs +19 -1
  466. package/hedhog/frontend/app/configurations/layout.tsx.ejs +19 -5
  467. package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +2 -8
  468. package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +3 -0
  469. package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +4 -0
  470. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +43 -44
  471. package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +41 -3
  472. package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +42 -2
  473. package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +41 -3
  474. package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +39 -4
  475. package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +42 -3
  476. package/hedhog/frontend/app/incidents/page.tsx.ejs +60 -31
  477. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +45 -5
  478. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +92 -15
  479. package/hedhog/frontend/app/mail/log/page.tsx.ejs +109 -61
  480. package/hedhog/frontend/app/mail/template/page.tsx.ejs +125 -23
  481. package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +13 -15
  482. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +116 -110
  483. package/hedhog/frontend/app/message-templates/_components/message-template-sheet.tsx.ejs +245 -0
  484. package/hedhog/frontend/app/message-templates/_lib/types.ts.ejs +24 -0
  485. package/hedhog/frontend/app/message-templates/page.tsx.ejs +182 -0
  486. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1 -0
  487. package/hedhog/frontend/app/pages/page.tsx.ejs +94 -9
  488. package/hedhog/frontend/app/roles/menus.tsx.ejs +4 -4
  489. package/hedhog/frontend/app/roles/routes.tsx.ejs +4 -4
  490. package/hedhog/frontend/app/roles/users.tsx.ejs +4 -4
  491. package/hedhog/frontend/app/setting-list/page.tsx.ejs +71 -9
  492. package/hedhog/frontend/app/users/page.tsx.ejs +77 -67
  493. package/hedhog/frontend/messages/en.json +183 -36
  494. package/hedhog/frontend/messages/pt.json +183 -36
  495. package/hedhog/table/cron_lock.yaml +17 -0
  496. package/hedhog/table/file.yaml +13 -1
  497. package/hedhog/table/file_upload_chunk.yaml +23 -0
  498. package/hedhog/table/file_upload_ticket.yaml +67 -0
  499. package/hedhog/table/mcp_tool_call_log.yaml +30 -22
  500. package/hedhog/table/message_template.yaml +33 -0
  501. package/hedhog/table/setting.yaml +8 -0
  502. package/hedhog/table/user_session.yaml +36 -1
  503. package/package.json +7 -5
  504. package/src/ai/ai-agent.sort.ts +21 -0
  505. package/src/ai/ai.service.spec.ts +173 -1
  506. package/src/ai/ai.service.ts +64 -193
  507. package/src/ai-instruction/ai-instruction.service.ts +32 -28
  508. package/src/ai-instruction/ai-instruction.sort.ts +32 -0
  509. package/src/auth/auth.module.ts +8 -1
  510. package/src/auth/auth.service.spec.ts +108 -1
  511. package/src/auth/auth.service.ts +59 -5
  512. package/src/auth/guards/auth.guard.ts +9 -1
  513. package/src/authorize/authorize.controller.ts +126 -11
  514. package/src/authorize/authorize.errors.ts +55 -0
  515. package/src/authorize/authorize.module.ts +6 -1
  516. package/src/authorize/authorize.service.spec.ts +379 -7
  517. package/src/authorize/authorize.service.ts +309 -23
  518. package/src/authorize/dto/authorize-info.dto.ts +21 -3
  519. package/src/authorize/dto/consent.dto.ts +21 -3
  520. package/src/authorize/dto/token.dto.ts +24 -2
  521. package/src/authorize/oauth-exception.filter.ts +58 -0
  522. package/src/authorize/oauth-metadata.service.ts +67 -0
  523. package/src/authorize/well-known.controller.spec.ts +84 -0
  524. package/src/authorize/well-known.controller.ts +96 -0
  525. package/src/captcha/captcha.service.spec.ts +211 -4
  526. package/src/captcha/captcha.service.ts +127 -10
  527. package/src/core.module.ts +6 -0
  528. package/src/dashboard/dashboard-component-role/dashboard-component-role.service.ts +2 -3
  529. package/src/dashboard/dashboard-component-role/dashboard-component-role.sort.ts +18 -0
  530. package/src/dashboard/dashboard-item/dashboard-item.service.ts +2 -3
  531. package/src/dashboard/dashboard-item/dashboard-item.sort.ts +19 -0
  532. package/src/dashboard/dashboard-role/dashboard-role.service.ts +2 -3
  533. package/src/dashboard/dashboard-role/dashboard-role.sort.ts +16 -0
  534. package/src/file/file-upload-ticket.service.spec.ts +422 -0
  535. package/src/file/file-upload-ticket.service.ts +513 -0
  536. package/src/file/file.controller.ts +65 -0
  537. package/src/file/file.module.ts +14 -2
  538. package/src/file/file.service.spec.ts +94 -0
  539. package/src/file/file.service.ts +433 -53
  540. package/src/file/filename-encoding.util.spec.ts +54 -0
  541. package/src/file/filename-encoding.util.ts +67 -0
  542. package/src/file/image-optimization.service.spec.ts +156 -19
  543. package/src/file/image-optimization.service.ts +106 -21
  544. package/src/file/mcp-file-source.schema.ts +83 -0
  545. package/src/file/mcp-file-source.service.spec.ts +473 -0
  546. package/src/file/mcp-file-source.service.ts +445 -0
  547. package/src/file/mimetype-sniff.util.spec.ts +126 -0
  548. package/src/file/mimetype-sniff.util.ts +265 -0
  549. package/src/file/remote-fetch.util.spec.ts +117 -0
  550. package/src/file/remote-fetch.util.ts +330 -0
  551. package/src/impersonation/dto/start-impersonation.dto.ts +5 -2
  552. package/src/impersonation/impersonation.service.spec.ts +24 -1
  553. package/src/impersonation/impersonation.service.ts +14 -4
  554. package/src/incident/incident.controller.ts +9 -1
  555. package/src/incident/incident.service.ts +7 -0
  556. package/src/index.ts +17 -0
  557. package/src/integration-profile/integration-profile.secrets.ts +7 -0
  558. package/src/integration-profile/integration-profile.service.ts +7 -64
  559. package/src/integration-profile/integration-profile.utils.spec.ts +9 -0
  560. package/src/integration-profile/integration-profile.utils.ts +5 -5
  561. package/src/integration-profile/testers/index.ts +2 -0
  562. package/src/integration-profile/testers/remaining.testers.spec.ts +79 -0
  563. package/src/integration-profile/testers/shipping.testers.ts +94 -0
  564. package/src/mail/dto/send.dto.ts +6 -1
  565. package/src/mail/mail-template.spec.ts +58 -1
  566. package/src/mail/mail.service.spec.ts +112 -0
  567. package/src/mail/mail.service.ts +42 -4
  568. package/src/mail-sent/mail-sent.service.ts +3 -0
  569. package/src/mail-sent/mail-sent.sort.ts +19 -0
  570. package/src/mcp/filters/mcp-challenge.filter.spec.ts +76 -0
  571. package/src/mcp/filters/mcp-challenge.filter.ts +70 -0
  572. package/src/mcp/guards/mcp-auth.guard.spec.ts +51 -2
  573. package/src/mcp/guards/mcp-auth.guard.ts +24 -1
  574. package/src/mcp/guards/mcp-permission.guard.spec.ts +109 -15
  575. package/src/mcp/guards/mcp-permission.guard.ts +76 -51
  576. package/src/mcp/mcp-audit.service.spec.ts +107 -0
  577. package/src/mcp/mcp-audit.service.ts +37 -1
  578. package/src/mcp/mcp-permission.service.spec.ts +197 -0
  579. package/src/mcp/mcp-permission.service.ts +184 -0
  580. package/src/mcp/mcp-server.service.spec.ts +84 -2
  581. package/src/mcp/mcp-server.service.ts +111 -87
  582. package/src/mcp/mcp.controller.ts +8 -1
  583. package/src/mcp/mcp.module.ts +5 -1
  584. package/src/mcp/tools/core-ai.mcp-tools.ts +1 -1
  585. package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +1 -1
  586. package/src/mcp/tools/core-dashboard.mcp-tools.ts +1 -1
  587. package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +1 -2
  588. package/src/mcp/tools/core-files.mcp-tools.ts +202 -22
  589. package/src/mcp/tools/core-integration-events.mcp-tools.ts +1 -1
  590. package/src/mcp/tools/core-mail-sent.mcp-tools.ts +1 -1
  591. package/src/mcp/tools/core-mail.mcp-tools.ts +1 -1
  592. package/src/mcp/tools/core-menus.mcp-tools.ts +1 -2
  593. package/src/mcp/tools/core-notifications.mcp-tools.ts +0 -1
  594. package/src/mcp/tools/core-roles.mcp-tools.ts +1 -5
  595. package/src/mcp/tools/core-routes.mcp-tools.ts +1 -3
  596. package/src/mcp/tools/core-screens.mcp-tools.ts +1 -3
  597. package/src/mcp/tools/core-sessions.mcp-tools.ts +0 -2
  598. package/src/mcp/tools/core-settings.mcp-tools.ts +1 -2
  599. package/src/mcp/tools/core-users.mcp-tools.ts +1 -1
  600. package/src/mcp/tools/core-webhooks.mcp-tools.ts +1 -2
  601. package/src/mcp/types/mcp-context.type.ts +15 -6
  602. package/src/mcp-chat/mcp-chat.service.ts +8 -0
  603. package/src/meeting/meeting-provider.registry.ts +121 -0
  604. package/src/meeting/meeting.constants.ts +74 -0
  605. package/src/menu/menu.service.spec.ts +89 -0
  606. package/src/menu/menu.service.ts +29 -11
  607. package/src/message-template/dto/update-message-template.dto.ts +22 -0
  608. package/src/message-template/message-template-admin.service.spec.ts +163 -0
  609. package/src/message-template/message-template-admin.service.ts +239 -0
  610. package/src/message-template/message-template.controller.ts +52 -0
  611. package/src/message-template/message-template.module.ts +21 -0
  612. package/src/message-template/message-template.registry.spec.ts +62 -0
  613. package/src/message-template/message-template.registry.ts +125 -0
  614. package/src/message-template/message-template.service.spec.ts +149 -0
  615. package/src/message-template/message-template.service.ts +149 -0
  616. package/src/notification/notification.constants.ts +10 -0
  617. package/src/notification/notification.module.ts +3 -0
  618. package/src/notification/notification.service.spec.ts +75 -1
  619. package/src/notification/notification.service.ts +39 -1
  620. package/src/oauth/oauth.controller.ts +0 -1
  621. package/src/oauth/oauth.errors.ts +7 -0
  622. package/src/oauth/oauth.module.ts +6 -1
  623. package/src/oauth/oauth.service.spec.ts +58 -7
  624. package/src/oauth/oauth.service.ts +71 -32
  625. package/src/oauth/providers/abstract.provider.spec.ts +192 -0
  626. package/src/oauth/providers/abstract.provider.ts +46 -14
  627. package/src/oauth/providers/github.provider.ts +57 -34
  628. package/src/oauth/providers/microsoft-entra-id.provider.ts +8 -1
  629. package/src/observability/monitored-cron.spec.ts +164 -31
  630. package/src/observability/monitored-cron.ts +154 -62
  631. package/src/profile/dto/change-password.dto.ts +25 -7
  632. package/src/profile/profile.service.spec.ts +97 -0
  633. package/src/profile/profile.service.ts +9 -3
  634. package/src/realtime/realtime-tick.coalescer.spec.ts +92 -0
  635. package/src/realtime/realtime-tick.coalescer.ts +60 -0
  636. package/src/realtime/realtime.service.spec.ts +33 -0
  637. package/src/realtime/realtime.service.ts +28 -2
  638. package/src/redis/redis-kv.service.ts +261 -0
  639. package/src/redis/redis-master.spec.ts +111 -0
  640. package/src/redis/redis-master.ts +86 -0
  641. package/src/redis/redis-pubsub.ts +27 -3
  642. package/src/redis/redis.module.ts +17 -0
  643. package/src/session/session.service.spec.ts +121 -42
  644. package/src/session/session.service.ts +279 -82
  645. package/src/setting/setting.service.ts +44 -3
  646. package/src/task/task.service.spec.ts +41 -0
  647. package/src/task/task.service.ts +53 -13
  648. package/src/token/token.service.spec.ts +90 -0
  649. package/src/token/token.service.ts +48 -2
  650. package/src/user/user-credential.util.ts +14 -5
  651. package/src/user/user.service.ts +2 -12
  652. package/src/user/user.sort.ts +25 -0
  653. package/src/utils/abbreviate-name.spec.ts +50 -0
  654. package/src/utils/abbreviate-name.ts +44 -0
  655. package/src/utils/date-range-query.dto.ts +56 -0
  656. package/src/utils/date-range.spec.ts +175 -0
  657. package/src/utils/date-range.ts +246 -0
  658. package/src/webhook-integration/webhook-utils.spec.ts +67 -0
  659. package/src/webhook-integration/webhook-utils.ts +26 -0
  660. package/src/whatsapp-sender/whatsapp-recipients.spec.ts +89 -0
  661. package/src/whatsapp-sender/whatsapp-recipients.ts +83 -0
  662. package/src/whatsapp-sender/whatsapp-sender.service.spec.ts +112 -0
  663. package/src/whatsapp-sender/whatsapp-sender.service.ts +58 -5
  664. package/hedhog/query/device_pairing_request.sql +0 -46
  665. package/hedhog/query/impersonation_grant.sql +0 -71
  666. package/hedhog/query/oauth_authorize_pkce.sql +0 -58
  667. package/hedhog/query/oauth_mobile_state_token.sql +0 -30
  668. package/hedhog/query/oauth_web_ref_token.sql +0 -25
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Nome de arquivo que chegou com o encoding trocado ("mojibake").
3
+ *
4
+ * O caso clássico é o byte a byte de UTF-8 lido como Latin-1: "Introdução" vira
5
+ * "Introdução". O multipart (busboy) entrega `originalname` assim, e a base
6
+ * ainda carrega nomes importados com o mesmo defeito — inclusive em duas camadas,
7
+ * quando o nome já quebrado passou pela conversão de novo ("IntroduÃ\u0083§Ã\u0083£o").
8
+ *
9
+ * A migration `20261103000000_core_fix_mojibake_filenames` reproduz esta mesma
10
+ * lógica em plpgsql para consertar o que já está gravado; mudanças aqui e lá
11
+ * andam juntas.
12
+ */
13
+
14
+ /** Quantas camadas de conversão desfazer antes de desistir. */
15
+ const MAX_DECODE_PASSES = 3;
16
+
17
+ /**
18
+ * Marca de nome quebrado. `Ã`/`Â` seguidos de qualquer coisa é o rastro do byte
19
+ * de continuação lido como caractere; `â` seguido de um byte alto é o começo de
20
+ * um caractere de 3 bytes (travessão, aspas curvas) quebrado do mesmo jeito.
21
+ */
22
+ const MOJIBAKE_PATTERN = /Ã.|Â.|â[\u0080-\u00BF]/;
23
+
24
+ export function hasMojibake(value: string): boolean {
25
+ return MOJIBAKE_PATTERN.test(value);
26
+ }
27
+
28
+ /**
29
+ * Desfaz as camadas de mojibake de `value`, ou devolve o original quando não dá
30
+ * para desfazer com segurança.
31
+ *
32
+ * Só aceita o resultado de uma passada se ele for UTF-8 válido: é isso que
33
+ * protege o nome legítimo que casa o padrão por acaso. "MANUTENÇÃO.pdf" tem
34
+ * "ÃO", mas os bytes Latin-1 correspondentes (`C7 C3 4F`) não formam UTF-8, o
35
+ * `Buffer` devolve `U+FFFD` e o nome sai intacto.
36
+ */
37
+ export function fixMojibake(value: string): string {
38
+ if (!value || !hasMojibake(value)) {
39
+ return value;
40
+ }
41
+
42
+ let current = value;
43
+
44
+ for (let pass = 0; pass < MAX_DECODE_PASSES; pass += 1) {
45
+ let decoded: string;
46
+ try {
47
+ decoded = Buffer.from(current, 'latin1').toString('utf8');
48
+ } catch {
49
+ break;
50
+ }
51
+
52
+ // `\uFFFD` é o que o decoder põe no lugar de byte inválido: o palpite estava
53
+ // errado e a passada anterior é o melhor que temos.
54
+ if (decoded === current || decoded.includes('\uFFFD')) {
55
+ break;
56
+ }
57
+
58
+ current = decoded;
59
+
60
+ if (!hasMojibake(current)) {
61
+ return current;
62
+ }
63
+ }
64
+
65
+ // Nenhuma passada chegou a um nome limpo: na dúvida, não estraga o que existe.
66
+ return hasMojibake(current) ? value : current;
67
+ }
@@ -20,16 +20,25 @@ import { ImageOptimizationService } from './image-optimization.service';
20
20
 
21
21
  const mockSharp = sharp as unknown as jest.Mock & { __instance: any };
22
22
 
23
- const DEFAULT_SETTINGS: Record<string, string | undefined> = {
24
- 'image-compression-enabled': 'false',
23
+ // O `SettingService` real converte o valor pelo `type` da setting antes de devolver:
24
+ // `boolean` vira boolean, `array` vira array JS. O mock precisa refletir isso, senão o
25
+ // spec valida um contrato que não existe — foi exatamente assim que a leitura por
26
+ // string passou despercebida e deixou compressão e WebP desligados em produção.
27
+ const DEFAULT_SETTINGS: Record<string, unknown> = {
28
+ 'image-compression-enabled': false,
25
29
  'image-compression-quality': undefined,
26
30
  'image-compression-types': undefined,
27
- 'image-webp-conversion-enabled': 'false',
31
+ 'image-webp-conversion-enabled': false,
28
32
  'image-webp-convert-types': undefined,
29
33
  'image-max-dimension': undefined,
30
34
  };
31
35
 
32
- const makeService = (settings: Record<string, string | undefined> = {}) => {
36
+ // Entrada grande o bastante para que qualquer saída simulada conte como ganho: o
37
+ // serviço recusa um resultado que não ficou menor, então um buffer de 3 bytes como
38
+ // entrada faria todo teste cair no fallback para o original.
39
+ const INPUT = Buffer.alloc(4096, 1);
40
+
41
+ const makeService = (settings: Record<string, unknown> = {}) => {
33
42
  const merged = { ...DEFAULT_SETTINGS, ...settings };
34
43
  const settingService = {
35
44
  getSettingValues: jest.fn(async () => merged),
@@ -135,12 +144,64 @@ describe('ImageOptimizationService', () => {
135
144
 
136
145
  it('retorna o original quando não há resize, compressão nem conversão', async () => {
137
146
  const { service } = makeService();
138
- const buffer = Buffer.from('img');
147
+ const buffer = INPUT;
139
148
  const result = await service.optimizeBuffer(buffer, 'image/jpeg', 'a.jpg');
140
149
  expect(result).toEqual({ buffer, mimetype: 'image/jpeg', originalname: 'a.jpg' });
141
150
  expect(mockSharp).not.toHaveBeenCalled();
142
151
  });
143
152
 
153
+ // Regressão: o SettingService devolve boolean e array já convertidos pelo `type` da
154
+ // setting. Ler isso como string desligava compressão e WebP mesmo com os toggles
155
+ // ligados na tela, e era o motivo de PNGs de vários MB serem gravados intactos.
156
+ it('converte para webp com as settings tipadas, como o SettingService entrega', async () => {
157
+ const { service } = makeService({
158
+ 'image-webp-conversion-enabled': true,
159
+ 'image-webp-convert-types': ['image/jpeg', 'image/png'],
160
+ 'image-compression-quality': 80,
161
+ });
162
+ const out = Buffer.from('webp-bytes');
163
+ mockSharp.__instance.toBuffer.mockResolvedValue(out);
164
+
165
+ const result = await service.optimizeBuffer(INPUT, 'image/png', 'skill.png');
166
+
167
+ expect(result).toEqual({
168
+ buffer: out,
169
+ mimetype: 'image/webp',
170
+ originalname: 'skill.webp',
171
+ });
172
+ expect(mockSharp.__instance.webp).toHaveBeenCalledWith({ quality: 80 });
173
+ });
174
+
175
+ it('comprime com as settings tipadas quando a conversão para webp está desligada', async () => {
176
+ const { service } = makeService({
177
+ 'image-compression-enabled': true,
178
+ 'image-compression-types': ['image/jpeg'],
179
+ 'image-compression-quality': 60,
180
+ });
181
+ const out = Buffer.from('jpeg-small');
182
+ mockSharp.__instance.toBuffer.mockResolvedValue(out);
183
+
184
+ const result = await service.optimizeBuffer(INPUT, 'image/jpeg', 'a.jpg');
185
+
186
+ expect(result).toEqual({ buffer: out, mimetype: 'image/jpeg', originalname: 'a.jpg' });
187
+ expect(mockSharp.__instance.jpeg).toHaveBeenCalledWith({ quality: 60 });
188
+ });
189
+
190
+ it('mantém o original quando o tipo tipado não está em nenhuma das listas', async () => {
191
+ const { service } = makeService({
192
+ 'image-compression-enabled': true,
193
+ 'image-compression-types': ['image/jpeg'],
194
+ 'image-webp-conversion-enabled': true,
195
+ 'image-webp-convert-types': ['image/jpeg'],
196
+ });
197
+ const buffer = Buffer.from('png-bytes');
198
+
199
+ const result = await service.optimizeBuffer(buffer, 'image/png', 'a.png');
200
+
201
+ expect(result).toEqual({ buffer, mimetype: 'image/png', originalname: 'a.png' });
202
+ expect(mockSharp).not.toHaveBeenCalled();
203
+ });
204
+
144
205
  it('converte para webp quando habilitado e o tipo está na lista', async () => {
145
206
  const { service } = makeService({
146
207
  'image-webp-conversion-enabled': 'true',
@@ -150,7 +211,7 @@ describe('ImageOptimizationService', () => {
150
211
  const out = Buffer.from('webp-bytes');
151
212
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
152
213
 
153
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/jpeg', 'photo.jpg');
214
+ const result = await service.optimizeBuffer(INPUT, 'image/jpeg', 'photo.jpg');
154
215
 
155
216
  expect(result).toEqual({
156
217
  buffer: out,
@@ -169,7 +230,7 @@ describe('ImageOptimizationService', () => {
169
230
  const out = Buffer.from('jpeg-small');
170
231
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
171
232
 
172
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/jpeg', 'a.jpg');
233
+ const result = await service.optimizeBuffer(INPUT, 'image/jpeg', 'a.jpg');
173
234
 
174
235
  expect(result).toEqual({ buffer: out, mimetype: 'image/jpeg', originalname: 'a.jpg' });
175
236
  expect(mockSharp.__instance.jpeg).toHaveBeenCalledWith({ quality: 60 });
@@ -184,7 +245,7 @@ describe('ImageOptimizationService', () => {
184
245
  const out = Buffer.from('png-small');
185
246
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
186
247
 
187
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/png', 'a.png');
248
+ const result = await service.optimizeBuffer(INPUT, 'image/png', 'a.png');
188
249
 
189
250
  expect(result.mimetype).toBe('image/png');
190
251
  // quality 80 -> compressionLevel 2
@@ -199,7 +260,7 @@ describe('ImageOptimizationService', () => {
199
260
  const out = Buffer.from('png-from-tiff');
200
261
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
201
262
 
202
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/tiff', 'scan.tiff');
263
+ const result = await service.optimizeBuffer(INPUT, 'image/tiff', 'scan.tiff');
203
264
 
204
265
  expect(result).toEqual({
205
266
  buffer: out,
@@ -213,7 +274,7 @@ describe('ImageOptimizationService', () => {
213
274
  const out = Buffer.from('resized');
214
275
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
215
276
 
216
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/jpeg', 'a.jpg');
277
+ const result = await service.optimizeBuffer(INPUT, 'image/jpeg', 'a.jpg');
217
278
 
218
279
  expect(mockSharp.__instance.resize).toHaveBeenCalledWith({
219
280
  width: 1024,
@@ -228,7 +289,7 @@ describe('ImageOptimizationService', () => {
228
289
  const { service } = makeService({ 'image-max-dimension': '1024' });
229
290
  mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.from('cropped'));
230
291
 
231
- await service.optimizeBuffer(Buffer.from('img'), 'image/jpeg', 'a.jpg', {
292
+ await service.optimizeBuffer(INPUT, 'image/jpeg', 'a.jpg', {
232
293
  maxWidth: 200,
233
294
  maxHeight: 100,
234
295
  });
@@ -245,13 +306,89 @@ describe('ImageOptimizationService', () => {
245
306
  const out = Buffer.from('reencoded');
246
307
  mockSharp.__instance.toBuffer.mockResolvedValue(out);
247
308
 
248
- const result = await service.optimizeBuffer(Buffer.from('img'), 'image/gif', 'a.gif');
309
+ const result = await service.optimizeBuffer(INPUT, 'image/heic', 'a.heic');
249
310
 
250
- expect(result).toEqual({ buffer: out, mimetype: 'image/gif', originalname: 'a.gif' });
311
+ expect(result).toEqual({ buffer: out, mimetype: 'image/heic', originalname: 'a.heic' });
251
312
  expect(mockSharp.__instance.jpeg).not.toHaveBeenCalled();
252
313
  expect(mockSharp.__instance.png).not.toHaveBeenCalled();
253
314
  });
254
315
 
316
+ it('não toca em SVG mesmo com max-dimension configurado (sharp não tem encoder de SVG)', async () => {
317
+ const { service } = makeService({ 'image-max-dimension': '500' });
318
+ const buffer = Buffer.from('<svg></svg>');
319
+
320
+ const result = await service.optimizeBuffer(buffer, 'image/svg+xml', 'logo.svg');
321
+
322
+ expect(result).toEqual({ buffer, mimetype: 'image/svg+xml', originalname: 'logo.svg' });
323
+ expect(mockSharp).not.toHaveBeenCalled();
324
+ });
325
+
326
+ it('não toca em GIF mesmo com max-dimension configurado (preserva a animação)', async () => {
327
+ const { service } = makeService({ 'image-max-dimension': '500' });
328
+ const buffer = Buffer.from('gif-bytes');
329
+
330
+ const result = await service.optimizeBuffer(buffer, 'image/gif', 'a.gif');
331
+
332
+ expect(result).toEqual({ buffer, mimetype: 'image/gif', originalname: 'a.gif' });
333
+ expect(mockSharp).not.toHaveBeenCalled();
334
+ });
335
+
336
+ // Recomprimir nem sempre encolhe: ilustração chapada e captura de tela com poucas
337
+ // cores costumam sair maiores em WebP com perda do que no PNG original. Gravar esse
338
+ // resultado inflaria justamente os arquivos que a feature deveria aliviar.
339
+ it('mantém o original quando o webp fica maior que a entrada', async () => {
340
+ const { service } = makeService({
341
+ 'image-webp-conversion-enabled': true,
342
+ 'image-webp-convert-types': ['image/png'],
343
+ });
344
+ const small = Buffer.alloc(64, 1);
345
+ mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.alloc(4096, 2));
346
+
347
+ const result = await service.optimizeBuffer(small, 'image/png', 'flat-art.png');
348
+
349
+ expect(result).toEqual({
350
+ buffer: small,
351
+ mimetype: 'image/png',
352
+ originalname: 'flat-art.png',
353
+ });
354
+ });
355
+
356
+ it('mantém o original quando a recompressão no mesmo formato fica maior', async () => {
357
+ const { service } = makeService({
358
+ 'image-compression-enabled': true,
359
+ 'image-compression-types': ['image/jpeg'],
360
+ });
361
+ const small = Buffer.alloc(64, 1);
362
+ mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.alloc(4096, 2));
363
+
364
+ const result = await service.optimizeBuffer(small, 'image/jpeg', 'a.jpg');
365
+
366
+ expect(result).toEqual({ buffer: small, mimetype: 'image/jpeg', originalname: 'a.jpg' });
367
+ });
368
+
369
+ // O recorte com dimensões exatas é a razão da chamada (capa de curso), não uma
370
+ // tentativa de encolher: devolver o original ali entregaria a proporção errada.
371
+ it('aceita resultado maior quando o alvo exato foi pedido (crop)', async () => {
372
+ const { service } = makeService({
373
+ 'image-webp-conversion-enabled': true,
374
+ 'image-webp-convert-types': ['image/png'],
375
+ });
376
+ const small = Buffer.alloc(64, 1);
377
+ const bigger = Buffer.alloc(4096, 2);
378
+ mockSharp.__instance.toBuffer.mockResolvedValue(bigger);
379
+
380
+ const result = await service.optimizeBuffer(small, 'image/png', 'banner.png', {
381
+ maxWidth: 1200,
382
+ maxHeight: 630,
383
+ });
384
+
385
+ expect(result).toEqual({
386
+ buffer: bigger,
387
+ mimetype: 'image/webp',
388
+ originalname: 'banner.webp',
389
+ });
390
+ });
391
+
255
392
  it('faz fallback para o original quando o sharp lança', async () => {
256
393
  const { service } = makeService({
257
394
  'image-compression-enabled': 'true',
@@ -261,7 +398,7 @@ describe('ImageOptimizationService', () => {
261
398
  const warnSpy = jest
262
399
  .spyOn((service as any).logger, 'warn')
263
400
  .mockImplementation(() => undefined);
264
- const buffer = Buffer.from('img');
401
+ const buffer = INPUT;
265
402
 
266
403
  const result = await service.optimizeBuffer(buffer, 'image/jpeg', 'a.jpg');
267
404
 
@@ -277,7 +414,7 @@ describe('ImageOptimizationService', () => {
277
414
  });
278
415
  mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.from('x'));
279
416
 
280
- await service.optimizeBuffer(Buffer.from('img'), 'image/jpeg', 'a.jpg');
417
+ await service.optimizeBuffer(INPUT, 'image/jpeg', 'a.jpg');
281
418
 
282
419
  expect(mockSharp.__instance.jpeg).toHaveBeenCalledWith({ quality: 80 });
283
420
  });
@@ -289,7 +426,7 @@ describe('ImageOptimizationService', () => {
289
426
  mockSharp.__instance.webp.mockReturnValue(mockSharp.__instance);
290
427
  mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.from('out'));
291
428
 
292
- const result = await service.resizeBuffer(Buffer.from('img'), 'image/jpeg', {
429
+ const result = await service.resizeBuffer(INPUT, 'image/jpeg', {
293
430
  width: 640,
294
431
  format: 'webp',
295
432
  quality: 82,
@@ -312,7 +449,7 @@ describe('ImageOptimizationService', () => {
312
449
  const { service } = makeService();
313
450
  mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.from('out'));
314
451
 
315
- const result = await service.resizeBuffer(Buffer.from('img'), 'image/png', {
452
+ const result = await service.resizeBuffer(INPUT, 'image/png', {
316
453
  width: 320,
317
454
  });
318
455
 
@@ -352,7 +489,7 @@ describe('ImageOptimizationService', () => {
352
489
  .mockImplementation(() => undefined);
353
490
  mockSharp.__instance.toBuffer.mockRejectedValue(new Error('sharp boom'));
354
491
 
355
- const result = await service.resizeBuffer(Buffer.from('img'), 'image/jpeg', {
492
+ const result = await service.resizeBuffer(INPUT, 'image/jpeg', {
356
493
  width: 640,
357
494
  });
358
495
 
@@ -364,7 +501,7 @@ describe('ImageOptimizationService', () => {
364
501
  const { service } = makeService();
365
502
  mockSharp.__instance.toBuffer.mockResolvedValue(Buffer.from('out'));
366
503
 
367
- await service.resizeBuffer(Buffer.from('img'), 'image/jpeg', {
504
+ await service.resizeBuffer(INPUT, 'image/jpeg', {
368
505
  width: 640,
369
506
  quality: 0,
370
507
  });
@@ -43,16 +43,36 @@ export class ImageOptimizationService {
43
43
  private readonly settingService: SettingService,
44
44
  ) {}
45
45
 
46
- private parseArraySetting(raw: string | undefined): string[] {
47
- if (!raw) return [];
46
+ /**
47
+ * `SettingService.getSettingValues` já converte o valor pelo `type` da setting: uma
48
+ * de tipo `array` chega aqui como array JS, não como a string do banco. Ler só a
49
+ * string fazia `JSON.parse` receber o array coagido para `"image/jpeg,image/png"`,
50
+ * lançar, e o catch devolver `[]` — o que desligava compressão e WebP em silêncio,
51
+ * por mais que os tipos estivessem marcados na tela. Aceitar as duas formas mantém
52
+ * o serviço utilizável por quem monta as settings à mão (specs, chamadores diretos).
53
+ */
54
+ private parseArraySetting(raw: unknown): string[] {
55
+ if (Array.isArray(raw)) {
56
+ return raw.map((item) => String(item));
57
+ }
58
+ if (typeof raw !== 'string' || !raw) return [];
48
59
  try {
49
60
  const parsed = JSON.parse(raw);
50
- return Array.isArray(parsed) ? parsed : [];
61
+ return Array.isArray(parsed) ? parsed.map((item) => String(item)) : [];
51
62
  } catch {
52
63
  return [];
53
64
  }
54
65
  }
55
66
 
67
+ /**
68
+ * Mesmo motivo do `parseArraySetting`: uma setting `boolean` chega como `true`, e
69
+ * comparar com a string `'true'` dava sempre `false`. É a mesma leitura tolerante
70
+ * que o `OAuthService` já faz.
71
+ */
72
+ private parseBooleanSetting(raw: unknown): boolean {
73
+ return raw === true || raw === 'true';
74
+ }
75
+
56
76
  private replaceExtension(filename: string, newExt: string): string {
57
77
  const base = basename(filename, extname(filename));
58
78
  return `${base}.${newExt}`;
@@ -88,6 +108,29 @@ export class ImageOptimizationService {
88
108
  }
89
109
  }
90
110
 
111
+ /**
112
+ * Recusa um resultado que não ficou menor que a entrada.
113
+ *
114
+ * Recomprimir nem sempre encolhe: ilustração chapada e captura de tela com poucas
115
+ * cores são casos em que o PNG original já é menor do que qualquer WebP com perda, e
116
+ * gravar o resultado maior contraria o próprio motivo de a feature existir. Pior, o
117
+ * `reoptimizeFile` autoriza a troca só pela mudança de mimetype — sem esta guarda, a
118
+ * varredura do acervo poderia inflar justamente os arquivos que ela deveria aliviar.
119
+ *
120
+ * Não vale quando o chamador pediu dimensões exatas (`maxWidth` + `maxHeight`): ali o
121
+ * recorte é a razão da chamada, e devolver o original entregaria a proporção errada.
122
+ */
123
+ private keepSmaller(
124
+ original: OptimizedImage,
125
+ optimized: OptimizedImage,
126
+ isExactCrop: boolean,
127
+ ): OptimizedImage {
128
+ if (isExactCrop || optimized.buffer.length < original.buffer.length) {
129
+ return optimized;
130
+ }
131
+ return original;
132
+ }
133
+
91
134
  /**
92
135
  * Applies optional resize, compression and/or WebP conversion to the given
93
136
  * buffer based on the current settings. Returns the original data unchanged
@@ -104,6 +147,17 @@ export class ImageOptimizationService {
104
147
  return { buffer, mimetype, originalname };
105
148
  }
106
149
 
150
+ // Vectors must stay vectors, and resizing an animated GIF would flatten it to a
151
+ // single frame — same reasoning as resizeBuffer() below. Sharp also has no SVG
152
+ // encoder: falling through to the generic "unknown format" branch re-encodes the
153
+ // rasterized result as PNG bytes while this function kept reporting the original
154
+ // `image/svg+xml` mimetype, so the stored file ended up with a Content-Type that
155
+ // didn't match its actual bytes and every consumer (the settings preview, the
156
+ // dynamic favicon, <img> tags) rendered a broken image.
157
+ if (mimetype === 'image/svg+xml' || mimetype === 'image/gif') {
158
+ return { buffer, mimetype, originalname };
159
+ }
160
+
107
161
  const settings = await this.settingService.getSettingValues([
108
162
  'image-compression-enabled',
109
163
  'image-compression-quality',
@@ -113,8 +167,12 @@ export class ImageOptimizationService {
113
167
  'image-max-dimension',
114
168
  ]);
115
169
 
116
- const compressionEnabled = settings['image-compression-enabled'] === 'true';
117
- const webpEnabled = settings['image-webp-conversion-enabled'] === 'true';
170
+ const compressionEnabled = this.parseBooleanSetting(
171
+ settings['image-compression-enabled'],
172
+ );
173
+ const webpEnabled = this.parseBooleanSetting(
174
+ settings['image-webp-conversion-enabled'],
175
+ );
118
176
 
119
177
  const quality = Math.min(
120
178
  100,
@@ -149,6 +207,9 @@ export class ImageOptimizationService {
149
207
  return { buffer, mimetype, originalname };
150
208
  }
151
209
 
210
+ const original: OptimizedImage = { buffer, mimetype, originalname };
211
+ const isExactCrop = targetWidth > 0 && targetHeight > 0;
212
+
152
213
  try {
153
214
  let instance = sharp(buffer);
154
215
  if (resize) {
@@ -158,50 +219,74 @@ export class ImageOptimizationService {
158
219
  // WebP conversion has priority over plain compression.
159
220
  if (willConvertWebp) {
160
221
  const optimized = await instance.webp({ quality }).toBuffer();
161
- return {
162
- buffer: optimized,
163
- mimetype: 'image/webp',
164
- originalname: this.replaceExtension(originalname, 'webp'),
165
- };
222
+ return this.keepSmaller(
223
+ original,
224
+ {
225
+ buffer: optimized,
226
+ mimetype: 'image/webp',
227
+ originalname: this.replaceExtension(originalname, 'webp'),
228
+ },
229
+ isExactCrop,
230
+ );
166
231
  }
167
232
 
168
233
  // Re-encode keeping the original format. Reached when compressing, or when
169
234
  // only resizing (a resize always requires re-encoding the buffer).
170
235
  if (mimetype === 'image/jpeg') {
171
236
  const optimized = await instance.jpeg({ quality }).toBuffer();
172
- return { buffer: optimized, mimetype, originalname };
237
+ return this.keepSmaller(
238
+ original,
239
+ { buffer: optimized, mimetype, originalname },
240
+ isExactCrop,
241
+ );
173
242
  } else if (mimetype === 'image/png') {
174
243
  const optimized = await instance
175
244
  .png({ compressionLevel: this.pngCompressionLevel(quality) })
176
245
  .toBuffer();
177
- return { buffer: optimized, mimetype, originalname };
246
+ return this.keepSmaller(
247
+ original,
248
+ { buffer: optimized, mimetype, originalname },
249
+ isExactCrop,
250
+ );
178
251
  } else if (mimetype === 'image/webp') {
179
252
  const optimized = await instance.webp({ quality }).toBuffer();
180
- return { buffer: optimized, mimetype, originalname };
253
+ return this.keepSmaller(
254
+ original,
255
+ { buffer: optimized, mimetype, originalname },
256
+ isExactCrop,
257
+ );
181
258
  } else if (mimetype === 'image/bmp' || mimetype === 'image/tiff') {
182
259
  // Convert to PNG as a compressed lossless alternative.
183
260
  const optimized = await instance
184
261
  .png({ compressionLevel: this.pngCompressionLevel(quality) })
185
262
  .toBuffer();
186
- return {
187
- buffer: optimized,
188
- mimetype: 'image/png',
189
- originalname: this.replaceExtension(originalname, 'png'),
190
- };
263
+ return this.keepSmaller(
264
+ original,
265
+ {
266
+ buffer: optimized,
267
+ mimetype: 'image/png',
268
+ originalname: this.replaceExtension(originalname, 'png'),
269
+ },
270
+ isExactCrop,
271
+ );
191
272
  }
192
273
 
193
274
  // Unknown image format: only re-encode if a resize was requested,
194
275
  // otherwise leave it untouched.
195
276
  if (resize) {
196
277
  const optimized = await instance.toBuffer();
197
- return { buffer: optimized, mimetype, originalname };
278
+ return this.keepSmaller(
279
+ original,
280
+ { buffer: optimized, mimetype, originalname },
281
+ isExactCrop,
282
+ );
198
283
  }
199
- return { buffer, mimetype, originalname };
284
+ return original;
200
285
  } catch (err) {
201
286
  this.logger.warn(
202
287
  `Image optimization failed for "${originalname}" (${mimetype}): ${err instanceof Error ? err.message : String(err)}. Falling back to original.`,
203
288
  );
204
- return { buffer, mimetype, originalname };
289
+ return original;
205
290
  }
206
291
  }
207
292
 
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Fragmento de schema e texto de descrição que toda tool MCP que recebe arquivo espalha
3
+ * no seu `inputSchema`.
4
+ *
5
+ * Fica num lugar só porque é ele que o modelo lê para decidir o caminho: se cada tool
6
+ * descrevesse as modalidades com palavras próprias, o agente escolheria diferente em cada
7
+ * uma, e a mais barata (`fileId`) perderia para a mais cara (`fileBase64`) por acidente
8
+ * de redação.
9
+ */
10
+
11
+ /** As quatro origens, em ordem de preferência. */
12
+ export const FILE_SOURCE_FIELDS = [
13
+ 'fileId',
14
+ 'uploadId',
15
+ 'fileUrl',
16
+ 'fileBase64',
17
+ ] as const;
18
+
19
+ export type FileSourceModality = (typeof FILE_SOURCE_FIELDS)[number];
20
+
21
+ /**
22
+ * Propriedades para espalhar no `inputSchema` da tool.
23
+ *
24
+ * Nenhuma delas entra em `required`: a exigência é "exatamente uma", que JSON Schema
25
+ * expressaria com `oneOf` mas que nem todo cliente MCP avalia — a checagem de verdade
26
+ * está em `McpFileSourceService.detectModality`, e a descrição abaixo é o que faz o
27
+ * modelo acertar antes de chamar.
28
+ */
29
+ export const FILE_SOURCE_SCHEMA_PROPERTIES: Record<string, any> = {
30
+ fileId: {
31
+ type: 'number',
32
+ description:
33
+ 'Preferred. ID of a file already in storage (from core.files.list, an attachments list, or core.files.upload.complete). Must have been uploaded by the caller, unless the caller is an administrator.',
34
+ },
35
+ uploadId: {
36
+ type: 'number',
37
+ description:
38
+ 'ID returned by core.files.create-upload-url or core.files.upload.init, after the binary has been uploaded. Use this to send a file that is on disk without putting its bytes in the conversation.',
39
+ },
40
+ fileUrl: {
41
+ type: 'string',
42
+ description:
43
+ 'Public http(s) URL the server downloads by itself. Private, loopback, link-local and cloud metadata addresses are rejected, redirects are limited, and the content type is checked against the actual bytes.',
44
+ },
45
+ fileBase64: {
46
+ type: 'string',
47
+ description:
48
+ 'Base64-encoded content, sent inline. Only for small files (about 256kb): base64 of anything larger overflows the model output limit. Requires fileName and mimeType.',
49
+ },
50
+ fileName: {
51
+ type: 'string',
52
+ description: 'Original file name. Required with fileBase64; optional with fileUrl.',
53
+ },
54
+ mimeType: {
55
+ type: 'string',
56
+ description:
57
+ 'MIME type, e.g. application/pdf. Required with fileBase64; optional with fileUrl. Must be allowed by the storage-accept-mimetype setting, and is verified against the real content.',
58
+ },
59
+ sha256: {
60
+ type: 'string',
61
+ description:
62
+ 'Optional hex sha256 of the file. When present, content that does not hash to it is rejected.',
63
+ },
64
+ };
65
+
66
+ /**
67
+ * Bloco anexado à descrição de cada tool.
68
+ *
69
+ * Diz o teto real — `storage-max-size`, 10 MB por padrão. A descrição antiga de
70
+ * `finance.titles.attachments.add` anunciava ~37 MB, número derivado do
71
+ * `api-body-size-limit`; ele nunca valeu, porque quem barra primeiro é o
72
+ * `storage-max-size`, e é ele que aparece na mensagem de erro.
73
+ */
74
+ export const FILE_SOURCE_DESCRIPTION = [
75
+ 'Exactly one file source is required: fileId, uploadId, fileUrl or fileBase64.',
76
+ 'Prefer fileId; use fileBase64 only for files of a few hundred kilobytes, since the encoded content has to fit in a single tool call.',
77
+ 'To send a local file without putting it in the conversation, call core.files.create-upload-url, PUT the binary to the URL it returns, call core.files.upload.complete, and pass the resulting fileId here.',
78
+ 'Every path enforces the storage-accept-mimetype and storage-max-size settings (10mb by default).',
79
+ ].join(' ');
80
+
81
+ /** Junta a descrição própria da tool com o bloco comum. */
82
+ export const withFileSourceDescription = (description: string): string =>
83
+ `${description.trim()} ${FILE_SOURCE_DESCRIPTION}`;