@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
@@ -24,6 +24,36 @@ type GeoIpResult = {
24
24
  export class SessionService {
25
25
  private readonly logger = new Logger(SessionService.name);
26
26
 
27
+ /**
28
+ * Janela em que o refresh token ANTERIOR continua sendo aceito depois de uma
29
+ * rotacao.
30
+ *
31
+ * Sem ela a rotacao e um handoff sem tolerancia: se a resposta do
32
+ * `/auth/refresh` se perde no caminho de volta — rede caindo, aba suspensa,
33
+ * pod reciclado no meio de um rollout — o servidor ja girou e o cliente fica
34
+ * com um token que nao vale mais. Uma sessao valida de 30 dias morre por um
35
+ * soluco de rede, e o unico rastro e um 401 solto. A janela tambem absorve
36
+ * duas abas renovando ao mesmo tempo.
37
+ *
38
+ * Curta de proposito: ela existe para cobrir a corrida e a resposta perdida,
39
+ * nao para prolongar a vida do token.
40
+ */
41
+ private static readonly REFRESH_GRACE_MS = 30_000;
42
+
43
+ /**
44
+ * Sessao aberta por um cliente OAuth externo vive menos que a de login: o
45
+ * refresh token esta com um terceiro. Vale na criacao E na renovacao — sem
46
+ * reaplicar aqui, a primeira renovacao devolvia a sessao aos 30 dias globais e
47
+ * o limite virava decoracao.
48
+ */
49
+ static readonly CONNECTOR_SESSION_TTL_MINUTES = 7 * 24 * 60;
50
+
51
+ /**
52
+ * Tentativas de rotacao por chamada. A segunda cobre o caso de outra
53
+ * requisicao ter girado a sessao entre a leitura e o compare-and-swap.
54
+ */
55
+ private static readonly REFRESH_ROTATION_ATTEMPTS = 2;
56
+
27
57
  constructor(
28
58
  private prisma: PrismaService,
29
59
  @Inject(forwardRef(() => SecurityService))
@@ -40,7 +70,19 @@ export class SessionService {
40
70
  private readonly paginationService: PaginationService,
41
71
  ) { }
42
72
 
43
- async create(locale: string, userId: number, ipAddress: string, userAgent: string, browserId?: string | null) {
73
+ /**
74
+ * `oauth` marca a sessao como pertencente a um cliente OAuth externo. Vem
75
+ * preenchido so pela troca do authorization code quando o cliente pediu um
76
+ * `resource`; o login normal continua chamando sem ele e nada muda.
77
+ */
78
+ async create(
79
+ locale: string,
80
+ userId: number,
81
+ ipAddress: string,
82
+ userAgent: string,
83
+ browserId?: string | null,
84
+ oauth?: { audience: string; clientId: string; ttlMinutes?: number },
85
+ ) {
44
86
  if (!userId) {
45
87
  throw new BadRequestException(getLocaleText('session.userIdRequired', locale, 'User ID is required to create a session.'));
46
88
  }
@@ -61,18 +103,34 @@ export class SessionService {
61
103
  const hash = this.security.hashWithPepper(token)
62
104
  const maxSessions = Number(settings['max-concurrent-sessions']) || 0;
63
105
 
64
- if (maxSessions > 0) {
106
+ // E pela mesma razao a sessao de conector nao DISPARA o despejo ao nascer.
107
+ // `createImpersonation` ja se isenta assim; aqui o efeito seria o usuario
108
+ // perder o celular por ter autorizado um app.
109
+ if (maxSessions > 0 && !oauth) {
65
110
  await this.enforceSessionLimit(userId, maxSessions, false, browserId);
66
111
  }
67
112
 
113
+ // Sessao de conector vive menos que a de login. Nao e simetria estetica: o
114
+ // refresh token esta com um terceiro, e 30 dias de janela para um segredo que
115
+ // saiu do nosso dominio e generoso demais.
116
+ //
117
+ // `||` e nao `??` em toda a cadeia: `Number(undefined)` e NaN, que passa
118
+ // direto por `??` e produziria um expires_at invalido.
119
+ const ttlMinutes =
120
+ oauth?.ttlMinutes ||
121
+ Number(settings['refresh-token-expiration-minutes']) ||
122
+ 43200;
123
+
68
124
  const session = await this.prisma.user_session.create({
69
125
  data: {
70
126
  user_id: userId,
71
127
  ip_address: ipAddress,
72
128
  user_agent: userAgent,
73
- expires_at: new Date(Date.now() + ((settings['refresh-token-expiration-minutes'] || 43200) * 60 * 1000)),
129
+ expires_at: new Date(Date.now() + ttlMinutes * 60 * 1000),
74
130
  hash,
75
131
  browser_id: browserId ?? null,
132
+ audience: oauth?.audience ?? null,
133
+ oauth_client_id: oauth?.clientId ?? null,
76
134
  },
77
135
  });
78
136
 
@@ -150,104 +208,221 @@ export class SessionService {
150
208
  }));
151
209
  }
152
210
 
153
- async refresh(locale: string, refreshToken: string, ipAddress: string, userAgent: string, browserId?: string | null) {
154
- if (!refreshToken) {
155
- throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
156
- }
157
-
158
- const hash = this.security.hashWithPepper(refreshToken);
159
-
160
- const rawSession = await this.prisma.user_session.findFirst({
161
- where: { hash },
162
- select: { id: true, user_id: true, ip_address: true, user_agent: true, revoked_at: true, expires_at: true, browser_id: true, impersonator_user_id: true },
163
- });
211
+ /**
212
+ * Anexa `oauth_client: { client_id, name }` as sessoes abertas por um cliente
213
+ * OAuth externo. Mesmo padrao de `attachImpersonators`, e pela mesma razao:
214
+ * `oauth_client_id` e VARCHAR puro, sem FK.
215
+ *
216
+ * Existe porque sem o nome a tela de seguranca do usuario fica ILEGIVEL para
217
+ * esse caso: um conector fala com a API a partir da nuvem do fornecedor, entao
218
+ * a linha aparece com user agent que o ua-parser nao reconhece
219
+ * (`python-httpx/0.28.1`), sem dispositivo, e geolocalizada no pais dele. Para
220
+ * quem esta no Brasil, e indistinguivel de uma conta invadida.
221
+ */
222
+ private async attachOAuthClients<T extends { oauth_client_id?: string | null }>(rows: T[]) {
223
+ const ids = Array.from(
224
+ new Set(
225
+ rows
226
+ .map((row) => row.oauth_client_id)
227
+ .filter((id): id is string => typeof id === 'string' && id.length > 0),
228
+ ),
229
+ );
164
230
 
165
- if (!rawSession) {
166
- this.logger.warn(`[SessionRefresh] Refresh rejected: hash prefix ${hash.slice(0, 8)} not found in DB`);
167
- throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
231
+ if (!ids.length) {
232
+ return rows.map((row) => ({ ...row, oauth_client: null }));
168
233
  }
169
234
 
170
- if (rawSession.revoked_at !== null) {
171
- this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} revoked_at=${rawSession.revoked_at.toISOString()} hash prefix ${hash.slice(0, 8)}`);
172
- throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
173
- }
235
+ const clients = await this.prisma.oauth_app_client.findMany({
236
+ where: { client_id: { in: ids } },
237
+ select: { client_id: true, name: true },
238
+ });
239
+ const byId = new Map(clients.map((client) => [client.client_id, client]));
174
240
 
175
- if (rawSession.expires_at <= new Date()) {
176
- this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} expired expires_at=${rawSession.expires_at.toISOString()} hash prefix ${hash.slice(0, 8)}`);
177
- throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
178
- }
241
+ return rows.map((row) => ({
242
+ ...row,
243
+ oauth_client: row.oauth_client_id
244
+ ? // Client removido do registro ainda tem sessao viva: cai no proprio
245
+ // slug, que e melhor que sumir com a informacao.
246
+ (byId.get(row.oauth_client_id) ?? {
247
+ client_id: row.oauth_client_id,
248
+ name: row.oauth_client_id,
249
+ })
250
+ : null,
251
+ }));
252
+ }
179
253
 
180
- // Simulacao de acesso e nao renovavel. `createImpersonation` ja descarta o
181
- // token opaco, entao chegar aqui significa que alguem obteve o segredo por
182
- // outro caminho — e renovar transformaria a janela de 30 minutos numa sessao
183
- // normal de 30 dias, sem a marca de simulado.
184
- if (rawSession.impersonator_user_id !== null) {
185
- this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} is an impersonation session`);
254
+ /**
255
+ * Gira o refresh token PRESERVANDO a identidade da sessao.
256
+ *
257
+ * A versao anterior revogava a linha e criava outra, com `id` novo. Como
258
+ * `TokenService.verify` valida a sessao no banco a cada request e recusa
259
+ * qualquer access token cuja sessao esteja revogada, o instante do refresh
260
+ * matava todos os access tokens em voo — na hora, e nao no `exp`. Numa tela
261
+ * que dispara ~10 chamadas em paralelo isso virava reacao em cadeia: cada 401
262
+ * disparava outro refresh, cada refresh matava os tokens dos outros. Nos logs
263
+ * de producao de 24/08 foram doze sessoes giradas em 18 segundos para o mesmo
264
+ * usuario, terminando em `Refresh rejected` e logout.
265
+ *
266
+ * Com o `id` estavel, o access token que ja saiu continua valido ate o proprio
267
+ * `exp`, e a rotacao deixa de ser um evento observavel pelo resto do app. De
268
+ * quebra a tabela para de crescer uma linha a cada 15 minutos por dispositivo.
269
+ */
270
+ async refresh(locale: string, refreshToken: string, ipAddress: string, userAgent: string, browserId?: string | null) {
271
+ if (!refreshToken) {
186
272
  throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
187
273
  }
188
274
 
189
- const session = {
190
- id: rawSession.id,
191
- user_id: rawSession.user_id,
192
- ip_address: rawSession.ip_address,
193
- user_agent: rawSession.user_agent,
194
- browser_id: rawSession.browser_id,
195
- };
275
+ const hash = this.security.hashWithPepper(refreshToken);
196
276
 
197
277
  const settings = await this.setting.getSettingValues([
198
278
  'refresh-token-expiration-minutes',
199
279
  'max-concurrent-sessions',
200
280
  ]);
201
-
202
281
  const maxSessions = Number(settings['max-concurrent-sessions']) || 0;
203
- if (maxSessions > 0) {
204
- await this.enforceSessionLimit(session.user_id, maxSessions, true, browserId);
205
- }
282
+ const ttlMinutes = Number(settings['refresh-token-expiration-minutes']) || 43200;
206
283
 
207
- const nextRefreshToken = await this.token.createOpaqueToken();
208
- const nextHash = this.security.hashWithPepper(nextRefreshToken);
209
- const expiresAt = new Date(Date.now() + ((settings['refresh-token-expiration-minutes'] || 43200) * 60 * 1000));
210
- const nextIpAddress = ipAddress?.trim() || session.ip_address || 'unknown';
211
- const nextUserAgent = userAgent?.trim() || session.user_agent || 'unknown';
284
+ for (let attempt = 1; attempt <= SessionService.REFRESH_ROTATION_ATTEMPTS; attempt++) {
285
+ const rawSession = await this.prisma.user_session.findFirst({
286
+ where: this.refreshTokenWhere(hash),
287
+ select: { id: true, user_id: true, ip_address: true, user_agent: true, revoked_at: true, expires_at: true, browser_id: true, impersonator_user_id: true, hash: true, audience: true, oauth_client_id: true },
288
+ });
212
289
 
213
- this.logger.debug(`[SessionRefresh] Starting rotation userId=${session.user_id} oldSessionId=${session.id} ip=${nextIpAddress}`);
214
- const txStart = Date.now();
290
+ if (!rawSession) {
291
+ this.logger.warn(`[SessionRefresh] Refresh rejected: hash prefix ${hash.slice(0, 8)} not found in DB`);
292
+ throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
293
+ }
294
+
295
+ if (rawSession.revoked_at !== null) {
296
+ this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} revoked_at=${rawSession.revoked_at.toISOString()} hash prefix ${hash.slice(0, 8)}`);
297
+ throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
298
+ }
299
+
300
+ if (rawSession.expires_at <= new Date()) {
301
+ this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} expired expires_at=${rawSession.expires_at.toISOString()} hash prefix ${hash.slice(0, 8)}`);
302
+ throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
303
+ }
304
+
305
+ // Simulacao de acesso e nao renovavel. `createImpersonation` ja descarta o
306
+ // token opaco, entao chegar aqui significa que alguem obteve o segredo por
307
+ // outro caminho — e renovar transformaria a janela de 30 minutos numa sessao
308
+ // normal de 30 dias, sem a marca de simulado.
309
+ if (rawSession.impersonator_user_id !== null) {
310
+ this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} is an impersonation session`);
311
+ throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
312
+ }
215
313
 
216
- const { updateResult, newSession } = await this.prisma.$transaction(async (tx) => {
217
- const updateResult = await tx.user_session.updateMany({
314
+ const nextRefreshToken = await this.token.createOpaqueToken();
315
+ const nextHash = this.security.hashWithPepper(nextRefreshToken);
316
+ const now = Date.now();
317
+ // Sessao de conector nao volta aos 30 dias globais so por ter sido
318
+ // renovada — o TTL curto e a propriedade que a distingue.
319
+ const effectiveTtl = rawSession.audience
320
+ ? Math.min(ttlMinutes, SessionService.CONNECTOR_SESSION_TTL_MINUTES)
321
+ : ttlMinutes;
322
+ const expiresAt = new Date(now + effectiveTtl * 60 * 1000);
323
+ const nextIpAddress = ipAddress?.trim() || rawSession.ip_address || 'unknown';
324
+ const nextUserAgent = userAgent?.trim() || rawSession.user_agent || 'unknown';
325
+
326
+ // Compare-and-swap pelo hash corrente, na MESMA linha. Se outra requisicao
327
+ // girou primeiro, `count` volta 0 e a proxima volta le o hash novo — em vez
328
+ // de devolver 401 para o perdedor da corrida, como antes.
329
+ const updateResult = await this.prisma.user_session.updateMany({
218
330
  where: {
219
- id: session.id,
331
+ id: rawSession.id,
220
332
  revoked_at: null,
333
+ hash: rawSession.hash,
221
334
  },
222
335
  data: {
223
- revoked_at: new Date(),
336
+ hash: nextHash,
337
+ previous_hash: rawSession.hash,
338
+ previous_hash_expires_at: new Date(now + SessionService.REFRESH_GRACE_MS),
339
+ expires_at: expiresAt,
340
+ ip_address: nextIpAddress,
341
+ user_agent: nextUserAgent,
342
+ browser_id: rawSession.browser_id ?? browserId ?? null,
343
+ updated_at: new Date(),
224
344
  },
225
345
  });
226
346
 
227
- const newSession = await tx.user_session.create({
228
- data: {
229
- user_id: session.user_id,
347
+ if (updateResult.count === 0) {
348
+ this.logger.debug(`[SessionRefresh] Rotation lost the CAS sessionId=${rawSession.id} userId=${rawSession.user_id} attempt=${attempt}`);
349
+ continue;
350
+ }
351
+
352
+ // Depois da rotacao, nunca antes. Rodando antes, o limite podia revogar a
353
+ // propria sessao que estava sendo renovada e o CAS falhava sozinho. E
354
+ // `keepSessionId` garante que renovar nunca despeja quem esta renovando.
355
+ if (maxSessions > 0) {
356
+ await this.enforceSessionLimit(rawSession.user_id, maxSessions, true, browserId, rawSession.id);
357
+ }
358
+
359
+ this.logger.debug(`[SessionRefresh] Rotation successful userId=${rawSession.user_id} sessionId=${rawSession.id} durationMs=${Date.now() - now}`);
360
+
361
+ return {
362
+ token: nextRefreshToken,
363
+ session: {
364
+ id: rawSession.id,
365
+ user_id: rawSession.user_id,
230
366
  ip_address: nextIpAddress,
231
367
  user_agent: nextUserAgent,
368
+ browser_id: rawSession.browser_id ?? browserId ?? null,
232
369
  expires_at: expiresAt,
233
- hash: nextHash,
234
- browser_id: session.browser_id ?? browserId ?? null,
370
+ // Quem renova precisa saber que esta renovando uma sessao de conector:
371
+ // e dai que sai o `aud` do proximo access token. Sem isso a rotacao
372
+ // devolveria um token de sessao comum e desfaria o vinculo.
373
+ audience: rawSession.audience ?? null,
374
+ oauth_client_id: rawSession.oauth_client_id ?? null,
235
375
  },
236
- });
376
+ };
377
+ }
237
378
 
238
- return { updateResult, newSession };
239
- });
379
+ this.logger.warn(`[SessionRefresh] Rotation gave up after ${SessionService.REFRESH_ROTATION_ATTEMPTS} attempts: hash prefix ${hash.slice(0, 8)}`);
380
+ throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
381
+ }
240
382
 
241
- if (updateResult.count === 0) {
242
- this.logger.warn(`[SessionRefresh] Race condition detected: userId=${session.user_id} oldSessionId=${session.id} already rotated by another request (durationMs=${Date.now() - txStart})`);
243
- throw new UnauthorizedException(getLocaleText('accessDenied', locale, 'Access denied.'));
244
- }
383
+ /**
384
+ * Casa o refresh token apresentado com a sessao: pelo hash corrente, ou pelo
385
+ * anterior enquanto a janela de graca estiver aberta.
386
+ *
387
+ * O limite pela janela e o que impede um token antigo qualquer de ressuscitar
388
+ * uma sessao — so o imediatamente anterior, e so por
389
+ * `REFRESH_GRACE_MS`, continua servindo.
390
+ */
391
+ /**
392
+ * Le a sessao de um refresh token SEM rotacionar nada.
393
+ *
394
+ * Existe porque `refresh()` encontra e gira na mesma operacao: quem precisa
395
+ * decidir se aceita a renovacao (o client confere? o resource confere? a sessao
396
+ * e de conector?) so podia fazer isso depois do compare-and-swap ja commitado —
397
+ * e uma recusa deixava o cliente com um token morto em 30 segundos, sem nunca
398
+ * receber o substituto. Validar antes e a diferenca entre negar um pedido e
399
+ * destruir a sessao.
400
+ */
401
+ async peekByRefreshToken(refreshToken: string) {
402
+ if (!refreshToken) return null;
245
403
 
246
- this.logger.debug(`[SessionRefresh] Rotation successful userId=${session.user_id} oldSessionId=${session.id} newSessionId=${newSession.id} durationMs=${Date.now() - txStart}`);
404
+ const hash = this.security.hashWithPepper(refreshToken);
405
+
406
+ return this.prisma.user_session.findFirst({
407
+ where: this.refreshTokenWhere(hash),
408
+ select: {
409
+ id: true,
410
+ user_id: true,
411
+ revoked_at: true,
412
+ expires_at: true,
413
+ audience: true,
414
+ oauth_client_id: true,
415
+ impersonator_user_id: true,
416
+ },
417
+ });
418
+ }
247
419
 
420
+ private refreshTokenWhere(hash: string) {
248
421
  return {
249
- token: nextRefreshToken,
250
- session: newSession,
422
+ OR: [
423
+ { hash },
424
+ { previous_hash: hash, previous_hash_expires_at: { gt: new Date() } },
425
+ ],
251
426
  };
252
427
  }
253
428
 
@@ -259,21 +434,20 @@ export class SessionService {
259
434
  }
260
435
 
261
436
  const hash = this.security.hashWithPepper(refreshToken);
437
+ // Aceita tambem o hash anterior dentro da janela de graca: sair da conta com
438
+ // um token que acabou de girar tem de derrubar a sessao de verdade, e nao
439
+ // devolver sucesso deixando-a viva.
440
+ const where = { revoked_at: null, ...this.refreshTokenWhere(hash) };
441
+
262
442
  const session = await this.prisma.user_session.findFirst({
263
- where: {
264
- revoked_at: null,
265
- hash,
266
- },
443
+ where,
267
444
  select: {
268
445
  user_id: true,
269
446
  },
270
447
  });
271
448
 
272
449
  const result = await this.prisma.user_session.updateMany({
273
- where: {
274
- revoked_at: null,
275
- hash,
276
- },
450
+ where,
277
451
  data: {
278
452
  revoked_at: new Date(),
279
453
  },
@@ -322,7 +496,7 @@ export class SessionService {
322
496
  );
323
497
 
324
498
  return {
325
- data: await this.attachImpersonators(itemsWithLocation),
499
+ data: await this.attachOAuthClients(await this.attachImpersonators(itemsWithLocation)),
326
500
  total: paginate.total || 0,
327
501
  lastPage: Math.ceil((paginate.total || 0) / (paginate.pageSize || 1)),
328
502
  page: paginate.page ?? 1,
@@ -373,7 +547,7 @@ export class SessionService {
373
547
  );
374
548
 
375
549
  return {
376
- data: await this.attachImpersonators(itemsWithLocation),
550
+ data: await this.attachOAuthClients(await this.attachImpersonators(itemsWithLocation)),
377
551
  total: paginate.total || 0,
378
552
  lastPage: Math.ceil((paginate.total || 0) / (paginate.pageSize || 1)),
379
553
  page: paginate.page ?? 1,
@@ -469,8 +643,11 @@ export class SessionService {
469
643
  * @param isRotation - When true, the calling flow is replacing an existing session (refresh),
470
644
  * not adding a new one, so no extra slot needs to be freed.
471
645
  * @param currentBrowserId - The browser_id of the session being created/refreshed.
646
+ * @param keepSessionId - Session that must survive: its whole browser slot is
647
+ * excluded from eviction. Passed by the refresh flow, so renewing a live
648
+ * session can never revoke the very session being renewed.
472
649
  */
473
- private async enforceSessionLimit(userId: number, maxSessions: number, isRotation = false, currentBrowserId?: string | null): Promise<void> {
650
+ private async enforceSessionLimit(userId: number, maxSessions: number, isRotation = false, currentBrowserId?: string | null, keepSessionId?: number): Promise<void> {
474
651
  const activeSessions = await this.prisma.user_session.findMany({
475
652
  where: {
476
653
  user_id: userId,
@@ -479,6 +656,11 @@ export class SessionService {
479
656
  // Simulacao de acesso nao consome slot: ela nasce com browser_id nulo e
480
657
  // seria contada como slot proprio, despejando uma sessao real do alvo.
481
658
  impersonator_user_id: null,
659
+ // Sessao de cliente OAuth externo, pelo mesmo motivo: um cliente MCP nao
660
+ // manda X-Browser-ID, entao cada conexao viraria um slot proprio e
661
+ // derrubaria um dispositivo de verdade do usuario — que so queria ligar o
662
+ // Claude. Conector nao e navegador.
663
+ audience: null,
482
664
  },
483
665
  orderBy: { created_at: 'asc' },
484
666
  select: { id: true, browser_id: true }
@@ -499,6 +681,16 @@ export class SessionService {
499
681
  const slots = Array.from(slotMap.values());
500
682
  const currentSlotCount = slots.length;
501
683
 
684
+ // O slot de quem esta renovando nunca entra na fila de despejo: renovar uma
685
+ // sessao viva nao pode derrubar a propria sessao. Sem isto, um usuario com
686
+ // mais slots que o limite era deslogado no proximo refresh — a rotacao
687
+ // revogava a si mesma e o compare-and-swap logo em seguida nao achava a
688
+ // linha.
689
+ const protectedSlot = typeof keepSessionId === 'number'
690
+ ? slots.find((slot) => slot.ids.includes(keepSessionId))
691
+ : undefined;
692
+ const evictable = slots.filter((slot) => slot !== protectedSlot);
693
+
502
694
  // A new browser slot is created only when:
503
695
  // - it's not a rotation (rotation keeps the same slot), AND
504
696
  // - the current browser doesn't already have an active slot
@@ -510,10 +702,15 @@ export class SessionService {
510
702
 
511
703
  if (slotsToRevoke > 0) {
512
704
  const sessionIdsToRevoke: number[] = [];
513
- for (let i = 0; i < slotsToRevoke; i++) {
514
- sessionIdsToRevoke.push(...slots[i].ids);
705
+ for (let i = 0; i < Math.min(slotsToRevoke, evictable.length); i++) {
706
+ sessionIdsToRevoke.push(...evictable[i].ids);
515
707
  }
516
- this.logger.warn(`[SessionLimit] Revoking ${slotsToRevoke} oldest browser slot(s) for userId=${userId}: sessions [${sessionIdsToRevoke.join(',')}]`);
708
+
709
+ if (sessionIdsToRevoke.length === 0) {
710
+ return;
711
+ }
712
+
713
+ this.logger.warn(`[SessionLimit] Revoking ${sessionIdsToRevoke.length} session(s) in the oldest browser slot(s) for userId=${userId}: [${sessionIdsToRevoke.join(',')}]`);
517
714
  await this.prisma.user_session.updateMany({
518
715
  where: { id: { in: sessionIdsToRevoke } },
519
716
  data: { revoked_at: new Date() }
@@ -0,0 +1,92 @@
1
+ import { NotFoundException } from '@nestjs/common';
2
+ import { FaviconController } from './favicon.controller';
3
+
4
+ const makeRes = () => {
5
+ const res: any = { headers: {} as Record<string, string> };
6
+ res.setHeader = jest.fn((k: string, v: string) => (res.headers[k] = v));
7
+ res.send = jest.fn((body: Buffer) => (res.body = body));
8
+ return res;
9
+ };
10
+
11
+ const makeController = (settings: Record<string, string>) => {
12
+ const setting = { getSettingValues: jest.fn().mockResolvedValue(settings) };
13
+ const brandAsset = {
14
+ resolveAssetUrl: jest.fn(async (value: string) =>
15
+ value.startsWith('/') ? `https://app.example.com${value}` : value,
16
+ ),
17
+ };
18
+ return new FaviconController(setting as any, brandAsset as any);
19
+ };
20
+
21
+ const svg = '<svg xmlns="http://www.w3.org/2000/svg"/>';
22
+
23
+ describe('FaviconController', () => {
24
+ const originalFetch = globalThis.fetch;
25
+ let fetchMock: jest.Mock;
26
+
27
+ beforeEach(() => {
28
+ fetchMock = jest.fn().mockResolvedValue(
29
+ new Response(svg, { headers: { 'content-type': 'image/svg+xml' } }),
30
+ );
31
+ globalThis.fetch = fetchMock as any;
32
+ });
33
+
34
+ afterEach(() => {
35
+ globalThis.fetch = originalFetch;
36
+ });
37
+
38
+ it('serves the Branding icon with the origin content type', async () => {
39
+ const controller = makeController({ 'icon-url': '/logo.svg' });
40
+ const res = makeRes();
41
+
42
+ await controller.favicon(res);
43
+
44
+ expect(fetchMock.mock.calls[0][0]).toBe('https://app.example.com/logo.svg');
45
+ expect(res.headers['Content-Type']).toBe('image/svg+xml');
46
+ expect(res.body.toString()).toBe(svg);
47
+ });
48
+
49
+ it('falls back to image-url and caches the download', async () => {
50
+ const controller = makeController({ 'icon-url': '', 'image-url': '/brand.svg' });
51
+
52
+ await controller.favicon(makeRes());
53
+ await controller.favicon(makeRes());
54
+
55
+ expect(fetchMock).toHaveBeenCalledTimes(1);
56
+ expect(fetchMock.mock.calls[0][0]).toBe('https://app.example.com/brand.svg');
57
+ });
58
+
59
+ it('decodes a data URI without fetching', async () => {
60
+ const png = Buffer.from([0x89, 0x50, 0x4e, 0x47]);
61
+ const controller = makeController({
62
+ 'icon-url': `data:image/png;base64,${png.toString('base64')}`,
63
+ });
64
+ const res = makeRes();
65
+
66
+ await controller.favicon(res);
67
+
68
+ expect(fetchMock).not.toHaveBeenCalled();
69
+ expect(res.headers['Content-Type']).toBe('image/png');
70
+ expect(Buffer.compare(res.body, png)).toBe(0);
71
+ });
72
+
73
+ it('answers 404 when the source is not an image', async () => {
74
+ fetchMock.mockResolvedValue(
75
+ new Response('<html/>', { headers: { 'content-type': 'text/html' } }),
76
+ );
77
+ const controller = makeController({ 'icon-url': '/logo.svg' });
78
+
79
+ await expect(controller.favicon(makeRes())).rejects.toBeInstanceOf(
80
+ NotFoundException,
81
+ );
82
+ });
83
+
84
+ it('answers 404 when nothing is configured', async () => {
85
+ const controller = makeController({});
86
+
87
+ await expect(controller.favicon(makeRes())).rejects.toBeInstanceOf(
88
+ NotFoundException,
89
+ );
90
+ expect(fetchMock).not.toHaveBeenCalled();
91
+ });
92
+ });