@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
@@ -3,6 +3,13 @@ import { Injectable, Logger } from '@nestjs/common';
3
3
  import { Cron, CronExpression } from '@nestjs/schedule';
4
4
  import { SettingService } from '../setting/setting.service';
5
5
 
6
+ /**
7
+ * Teto de tempo da limpeza do `access_log`. Existe para o caso da entrada
8
+ * superar a saída de novo: o laço para e devolve o resto para a execução
9
+ * seguinte, em vez de varrer a madrugada inteira disputando o banco.
10
+ */
11
+ const ACCESS_LOG_CLEANUP_BUDGET_MS = 10 * 60 * 1000;
12
+
6
13
  @Injectable()
7
14
  export class TasksService {
8
15
  private readonly logger = new Logger(TasksService.name);
@@ -270,6 +277,23 @@ export class TasksService {
270
277
  );
271
278
  }
272
279
 
280
+ /**
281
+ * Apaga os logs de acesso fora da janela de `access-log-retention-days`.
282
+ *
283
+ * Roda em lotes até drenar, e não em um lote só. O `access_log` recebe um
284
+ * INSERT por requisição — em produção, de 200 a 540 mil por dia — enquanto a
285
+ * limpeza apagava `cleanup-batch-limit` registros por execução diária. Com a
286
+ * entrada uma ordem de grandeza acima da saída, a retenção nunca era
287
+ * alcançada: a tabela chegou a 18,6 milhões de linhas e 4 GB, com 11,8
288
+ * milhões já vencidos e registros três meses mais velhos que a retenção de 30
289
+ * dias configurada.
290
+ *
291
+ * O `cleanup-batch-limit` passa a ser o tamanho de CADA lote — o papel que a
292
+ * própria descrição da setting sempre anunciou ("valores menores evitam locks
293
+ * prolongados mas aumentam a duração da limpeza"). O teto agora é de tempo,
294
+ * não de linhas: o laço para ao drenar a fila ou ao estourar o orçamento,
295
+ * para que a limpeza não avance madrugada adentro competindo com o tráfego.
296
+ */
273
297
  private async clearOldAccessLogs(): Promise<void> {
274
298
  const settings = await this.settingService.getSettingValues([
275
299
  'cleanup-batch-limit',
@@ -280,21 +304,37 @@ export class TasksService {
280
304
  this.logger.verbose('Starting cleanup of old access logs');
281
305
  const startAt = Date.now();
282
306
 
283
- await this.prismaService.$executeRaw`
284
- WITH del AS (
285
- SELECT id
286
- FROM access_log
287
- WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
288
- ORDER BY id
289
- LIMIT ${batchLimit}
290
- )
291
- DELETE FROM access_log al
292
- USING del
293
- WHERE al.id = del.id
294
- `;
307
+ let deleted = 0;
308
+ let batches = 0;
309
+ for (;;) {
310
+ const removed = await this.prismaService.$executeRaw`
311
+ WITH del AS (
312
+ SELECT id
313
+ FROM access_log
314
+ WHERE created_at < (now() - ${Prisma.sql`INTERVAL '${Prisma.raw(String(retentionDays))} days'`})
315
+ ORDER BY id
316
+ LIMIT ${batchLimit}
317
+ )
318
+ DELETE FROM access_log al
319
+ USING del
320
+ WHERE al.id = del.id
321
+ `;
322
+
323
+ deleted += removed;
324
+ batches += 1;
325
+
326
+ if (removed < batchLimit) break;
327
+
328
+ if (Date.now() - startAt >= ACCESS_LOG_CLEANUP_BUDGET_MS) {
329
+ this.logger.warn(
330
+ `Access log cleanup hit the ${ACCESS_LOG_CLEANUP_BUDGET_MS}ms budget after ${deleted} rows; the remainder goes on the next run.`,
331
+ );
332
+ break;
333
+ }
334
+ }
295
335
 
296
336
  this.logger.verbose(
297
- `Old access logs cleaned up in ${Date.now() - startAt}ms`,
337
+ `Old access logs cleaned up in ${Date.now() - startAt}ms (${deleted} rows in ${batches} batches)`,
298
338
  );
299
339
  }
300
340
 
@@ -410,4 +410,94 @@ describe('TokenService', () => {
410
410
  );
411
411
  });
412
412
  });
413
+
414
+ describe('verify - audiencia (audience binding)', () => {
415
+ const RESOURCE = 'https://hub-api.example.com/mcp';
416
+ const activeSession = {
417
+ revoked_at: null,
418
+ expires_at: new Date(Date.now() + 60_000),
419
+ };
420
+
421
+ // ESTE e o teste central do audience binding: sem ele, o token entregue ao
422
+ // conector do Claude valeria na API REST inteira.
423
+ it('recusa token COM aud numa rota que nao declara recurso', async () => {
424
+ const { service, deps } = makeService();
425
+ deps.jwt.verifyAsync.mockResolvedValue({ sub: 1, sessionId: 9, aud: RESOURCE });
426
+
427
+ await expect(service.verify('en', 'tok')).rejects.toThrow(
428
+ UnauthorizedException,
429
+ );
430
+ // Nem chega a consultar a sessao: a recusa e antes.
431
+ expect(deps.prisma.user_session.findUnique).not.toHaveBeenCalled();
432
+ });
433
+
434
+ it('recusa token cujo aud e de OUTRO recurso', async () => {
435
+ const { service, deps } = makeService();
436
+ deps.jwt.verifyAsync.mockResolvedValue({
437
+ sub: 1,
438
+ sessionId: 9,
439
+ aud: 'https://outro.example.com/mcp',
440
+ });
441
+
442
+ await expect(service.verify('en', 'tok', RESOURCE)).rejects.toThrow(
443
+ UnauthorizedException,
444
+ );
445
+ });
446
+
447
+ it('aceita token cujo aud casa exatamente com o recurso', async () => {
448
+ const { service, deps } = makeService();
449
+ deps.jwt.verifyAsync.mockResolvedValue({ sub: 1, sessionId: 9, aud: RESOURCE });
450
+ deps.prisma.user_session.findUnique.mockResolvedValue(activeSession);
451
+
452
+ await expect(service.verify('en', 'tok', RESOURCE)).resolves.toMatchObject({
453
+ sub: 1,
454
+ aud: RESOURCE,
455
+ });
456
+ });
457
+
458
+ // Comparacao por igualdade exata: barra final e outro recurso.
459
+ it('nao normaliza barra final ao comparar', async () => {
460
+ const { service, deps } = makeService();
461
+ deps.jwt.verifyAsync.mockResolvedValue({
462
+ sub: 1,
463
+ sessionId: 9,
464
+ aud: RESOURCE + '/',
465
+ });
466
+
467
+ await expect(service.verify('en', 'tok', RESOURCE)).rejects.toThrow(
468
+ UnauthorizedException,
469
+ );
470
+ });
471
+
472
+ // O login normal nao pode mudar de comportamento por causa disso.
473
+ it('aceita token SEM aud, com ou sem recurso declarado', async () => {
474
+ const { service, deps } = makeService();
475
+ deps.jwt.verifyAsync.mockResolvedValue({ sub: 1, sessionId: 9 });
476
+ deps.prisma.user_session.findUnique.mockResolvedValue(activeSession);
477
+
478
+ await expect(service.verify('en', 'tok')).resolves.toMatchObject({ sub: 1 });
479
+ await expect(service.verify('en', 'tok', RESOURCE)).resolves.toMatchObject({
480
+ sub: 1,
481
+ });
482
+ });
483
+
484
+ it('falha fechado em erro de banco quando o token e de recurso', async () => {
485
+ const { service, deps } = makeService();
486
+ deps.jwt.verifyAsync.mockResolvedValue({ sub: 1, sessionId: 9, aud: RESOURCE });
487
+ deps.prisma.user_session.findUnique.mockRejectedValue(new Error('db down'));
488
+
489
+ await expect(service.verify('en', 'tok', RESOURCE)).rejects.toThrow(
490
+ UnauthorizedException,
491
+ );
492
+ });
493
+
494
+ it('segue aberto em erro de banco para a sessao de login', async () => {
495
+ const { service, deps } = makeService();
496
+ deps.jwt.verifyAsync.mockResolvedValue({ sub: 1, sessionId: 9 });
497
+ deps.prisma.user_session.findUnique.mockRejectedValue(new Error('db down'));
498
+
499
+ await expect(service.verify('en', 'tok')).resolves.toMatchObject({ sub: 1 });
500
+ });
501
+ });
502
+
413
503
  });
@@ -22,13 +22,46 @@ export class TokenService {
22
22
  private readonly setting: SettingService,
23
23
  ) { }
24
24
 
25
- async verify(locale: string, token: string) {
25
+ /**
26
+ * `allowedAudience` declara qual recurso ESTA rota atende. A regra e de mao
27
+ * unica, e e essa assimetria que faz o modelo funcionar:
28
+ *
29
+ * - token SEM `aud` (o login normal) vale em qualquer lugar, com ou sem o
30
+ * parametro — nada muda para quem ja existe;
31
+ * - token COM `aud` so vale onde aquele exato recurso foi declarado. Em
32
+ * qualquer outra rota, 401.
33
+ *
34
+ * O AuthGuard global chama este metodo SEM o terceiro argumento, entao toda
35
+ * rota que ninguem marcou como recurso ja recusa um token de conector — por
36
+ * construcao, inclusive nas rotas que ainda nem foram escritas. Nao ha
37
+ * allowlist para alguem esquecer de atualizar.
38
+ *
39
+ * A comparacao e feita aqui, na mao, e nao pela opcao `audience` do
40
+ * jsonwebtoken: quando aquela opcao esta ausente, a lib simplesmente NAO OLHA o
41
+ * claim. E exatamente essa omissao que precisa virar rejeicao.
42
+ */
43
+ async verify(locale: string, token: string, allowedAudience?: string) {
26
44
  try {
27
45
 
28
46
  const payload = await this.jwt.verifyAsync(token, {
29
47
  secret: this.security.getJwtSecret(),
30
48
  });
31
49
 
50
+ const audience = payload.aud;
51
+ const isResourceToken = audience !== undefined;
52
+
53
+ // Igualdade exata de string, sem parsear URL — normalizar abriria as mesmas
54
+ // brechas que a allowlist de redirect_uri ja evita (barra final, case do
55
+ // host, porta default).
56
+ if (isResourceToken && audience !== allowedAudience) {
57
+ this.logger.warn(
58
+ `[TokenVerify] sessionId=${payload.sessionId} userId=${payload.sub} token with aud=${audience} used outside its resource`,
59
+ );
60
+ throw new UnauthorizedException(
61
+ getLocaleText('accessDenied', locale, 'Access denied.'),
62
+ );
63
+ }
64
+
32
65
  // Verify session is not revoked (only if prisma is available)
33
66
  if (payload.sessionId && this.prisma) {
34
67
  try {
@@ -62,8 +95,21 @@ export class TokenService {
62
95
  if (sessionError instanceof UnauthorizedException) {
63
96
  throw sessionError;
64
97
  }
65
- // DB error: log but allow auth to continue to avoid blocking on transient DB issues
66
98
  this.logger.error(`[TokenVerify] DB error validating sessionId=${payload.sessionId} userId=${payload.sub}: ${(sessionError as any)?.message}`);
99
+
100
+ // Token de recurso nao ganha o beneficio da duvida. Para a sessao de
101
+ // login, seguir em frente numa falha transitoria de banco e a troca
102
+ // certa — derrubar todo mundo logado e pior que aceitar uma revogacao
103
+ // com atraso. Para um token entregue a um cliente externo, user_session
104
+ // e o UNICO jeito de revogar: continuar aqui faria uma revogacao valer
105
+ // so no vencimento do JWT. A decisao segue a natureza do TOKEN, nao a
106
+ // da rota.
107
+ if (isResourceToken) {
108
+ throw new UnauthorizedException(
109
+ getLocaleText('accessDenied', locale, 'Access denied.'),
110
+ );
111
+ }
112
+ // DB error: log but allow auth to continue to avoid blocking on transient DB issues
67
113
  }
68
114
  }
69
115
 
@@ -21,15 +21,24 @@ export function hasPendingPasswordReset(user: any): boolean {
21
21
  );
22
22
  }
23
23
 
24
+ /**
25
+ * Credencial de senha que ainda vale: do tipo password e não revogada.
26
+ *
27
+ * Existe para quem já tem as credenciais em memória e precisa do mesmo critério
28
+ * que as consultas de Prisma expressam com `revoked_at: null`. O login e a troca
29
+ * de e-mail filtravam só por `type`, então uma credencial revogada continuava
30
+ * autenticando — e a revogação é justamente o que o convite de acesso enterprise
31
+ * usa para transformar "autorize o acesso" em "crie sua conta e defina a senha".
32
+ */
33
+ export function isActivePasswordCredential(credential: any): boolean {
34
+ return credential?.type === 'password' && !credential?.revoked_at;
35
+ }
36
+
24
37
  /**
25
38
  * Usuários criados/autenticados apenas via provedor externo (ex: Microsoft
26
39
  * Entra ID) nunca têm uma credencial de senha ativa — não faz sentido
27
40
  * oferecer o fluxo de "esqueci a senha" para eles.
28
41
  */
29
42
  export function hasPasswordCredential(user: any): boolean {
30
- return Boolean(
31
- user?.user_credential?.some(
32
- (credential) => credential?.type === 'password' && !credential?.revoked_at,
33
- ),
34
- );
43
+ return Boolean(user?.user_credential?.some(isActivePasswordCredential));
35
44
  }
@@ -25,6 +25,7 @@ import {
25
25
  PENDING_PASSWORD_RESET_WHERE,
26
26
  hasPendingPasswordReset,
27
27
  } from './user-credential.util';
28
+ import { USER_SORT } from './user.sort';
28
29
 
29
30
  // Constants
30
31
  const IDENTIFIER_TYPE = {
@@ -48,17 +49,6 @@ const PASSWORD_CHARSETS = {
48
49
  symbols: '@#$%&*!?-_+',
49
50
  } as const;
50
51
 
51
- const USER_SORT_FIELDS = [
52
- 'id',
53
- 'name',
54
- 'photo_id',
55
- 'suspended_until',
56
- 'suspended_reason',
57
- 'deactivated_at',
58
- 'created_at',
59
- 'updated_at',
60
- ] as const;
61
-
62
52
  type UserChangeLog = user_change_log;
63
53
  type UserChangeLogActor = Prisma.userGetPayload<{
64
54
  select: {
@@ -164,7 +154,7 @@ export class UserService {
164
154
  this.prismaService.user,
165
155
  {
166
156
  ...paginationParams,
167
- validSortFields: USER_SORT_FIELDS,
157
+ sort: USER_SORT,
168
158
  where: this.buildUserListWhere(filter, paginationParams?.search),
169
159
  include: this.getUserIncludeClause(),
170
160
  }
@@ -0,0 +1,25 @@
1
+ import { defineSortable } from '@hed-hog/api-pagination';
2
+
3
+ /**
4
+ * Campos ordenáveis de `user`.
5
+ *
6
+ * `email` fica de fora: mora em `user_identifier` (relação to-many filtrada
7
+ * por `type = 'email'`), sem coluna própria em `user` para o Prisma ordenar —
8
+ * mesma limitação documentada em `libraries/lms/src/instructor/instructor.sort.ts`
9
+ * para o e-mail do instrutor.
10
+ *
11
+ * `passwordReset` também fica de fora: é booleano calculado no service
12
+ * (`hasPendingPasswordReset`), não uma coluna.
13
+ *
14
+ * Sem ninguém pedir ordenação, o resultado continua igual ao de antes
15
+ * (`id` desc, o fallback do `paginatePrismaModel` quando não há `sortField`).
16
+ */
17
+ export const USER_SORT = defineSortable(
18
+ {
19
+ name: true,
20
+ suspended_until: true,
21
+ last_login_at: true,
22
+ id: { initialOrder: 'desc' },
23
+ },
24
+ { default: 'id', defaultOrder: 'desc' },
25
+ );
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import { abbreviateName } from './abbreviate-name';
3
+
4
+ describe('abbreviateName', () => {
5
+ it('mantém primeiro nome e último sobrenome', () => {
6
+ expect(abbreviateName('João Henrique Cunha Rangel')).toBe('João Rangel');
7
+ });
8
+
9
+ it('ignora partículas (de/da/do/das/dos/e) ao escolher o último sobrenome', () => {
10
+ expect(abbreviateName('Maria de Souza')).toBe('Maria Souza');
11
+ expect(abbreviateName('Ana da Silva')).toBe('Ana Silva');
12
+ expect(abbreviateName('Pedro dos Santos')).toBe('Pedro Santos');
13
+ expect(abbreviateName('Carlos do Nascimento')).toBe('Carlos Nascimento');
14
+ expect(abbreviateName('José das Neves')).toBe('José Neves');
15
+ expect(abbreviateName('Silva e Souza Junior')).toBe('Silva Junior');
16
+ });
17
+
18
+ it('nome com duas palavras não muda', () => {
19
+ expect(abbreviateName('Ana Paula')).toBe('Ana Paula');
20
+ });
21
+
22
+ it('nome com uma palavra só passa como está', () => {
23
+ expect(abbreviateName('Madonna')).toBe('Madonna');
24
+ });
25
+
26
+ it('nome vazio ou só espaço devolve vazio', () => {
27
+ expect(abbreviateName('')).toBe('');
28
+ expect(abbreviateName(' ')).toBe('');
29
+ });
30
+
31
+ it('nome nulo/indefinido devolve vazio', () => {
32
+ expect(abbreviateName(null)).toBe('');
33
+ expect(abbreviateName(undefined)).toBe('');
34
+ });
35
+
36
+ it('normaliza espaços múltiplos entre palavras', () => {
37
+ expect(abbreviateName(' João Henrique Rangel ')).toBe('João Rangel');
38
+ });
39
+
40
+ it('cai no primeiro nome quando só sobra partícula depois dele', () => {
41
+ // Dado maltratado (ex.: sobrenome vazio salvo como "de") — não deve
42
+ // repetir o primeiro nome nem devolver a partícula sozinha.
43
+ expect(abbreviateName('João de')).toBe('João');
44
+ });
45
+
46
+ it('fallback "Alguém"/"Someone" (sem atribuidor) passa direto, sem quebrar', () => {
47
+ expect(abbreviateName('Alguém')).toBe('Alguém');
48
+ expect(abbreviateName('Someone')).toBe('Someone');
49
+ });
50
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Partículas ignoradas ao escolher o "último sobrenome" — sem isso, "Maria de
3
+ * Souza" viraria "Maria de" em vez de "Maria Souza".
4
+ */
5
+ const NAME_PARTICLES = new Set(['de', 'da', 'do', 'das', 'dos', 'e']);
6
+
7
+ /**
8
+ * Abrevia um nome completo para "primeiro nome + último sobrenome", o formato
9
+ * usado nos templates de e-mail transacional (ex.: `operations-task-assigned`)
10
+ * pra não estampar o nome completo do colaborador — "João Henrique Cunha
11
+ * Rangel" vira "João Rangel".
12
+ *
13
+ * Partículas (de/da/do/das/dos/e) são ignoradas na escolha do último
14
+ * sobrenome, não removidas do nome inteiro — só afetam qual token conta como
15
+ * "o último". Nome com uma palavra só, vazio ou nulo passa como está (nada a
16
+ * abreviar).
17
+ */
18
+ export function abbreviateName(fullName?: string | null): string {
19
+ const trimmed = (fullName ?? '').trim();
20
+ if (!trimmed) {
21
+ return trimmed;
22
+ }
23
+
24
+ const words = trimmed.split(/\s+/);
25
+ if (words.length === 1) {
26
+ return words[0];
27
+ }
28
+
29
+ const firstName = words[0];
30
+
31
+ // Anda de trás pra frente até achar um token que não seja partícula. Se
32
+ // todos os tokens depois do primeiro forem partícula (dado maltratado),
33
+ // cai no primeiro nome sozinho em vez de repetir "João de" ou "João João".
34
+ let lastIndex = words.length - 1;
35
+ while (lastIndex > 0 && NAME_PARTICLES.has(words[lastIndex].toLowerCase())) {
36
+ lastIndex--;
37
+ }
38
+
39
+ if (lastIndex === 0) {
40
+ return firstName;
41
+ }
42
+
43
+ return `${firstName} ${words[lastIndex]}`;
44
+ }
@@ -0,0 +1,56 @@
1
+ import { Transform } from 'class-transformer';
2
+ import { IsDateString, IsOptional } from 'class-validator';
3
+
4
+ /**
5
+ * `?from=yyyy-MM-dd&to=yyyy-MM-dd` — o par padrão de recorte por período de
6
+ * toda listagem nova. Endpoint que já tem nome próprio (`dateFrom`/`dateTo` da
7
+ * fila, `createdAtFrom`/`createdAtTo` do mail-sent, `date_from`/`date_to` do
8
+ * sac) mantém o nome dele: só o que nasce daqui em diante usa `from`/`to`.
9
+ *
10
+ * Composto, e não herdado de `PaginationDTO`, porque quase todo adotante é o
11
+ * **segundo** argumento `@Query()` do controller, ao lado do `@Pagination()` —
12
+ * que descarta tudo que não é paginação. Carregar `page`/`pageSize` junto
13
+ * duplicaria campo que o DTO de filtro não é dono. Onde o DTO de filtro já
14
+ * estende `PaginationDTO`, o jeito de juntar os dois é o `IntersectionType`:
15
+ *
16
+ * ```ts
17
+ * export class ListContractsDto extends IntersectionType(
18
+ * PaginationDTO,
19
+ * DateRangeQueryDTO,
20
+ * ) {}
21
+ * ```
22
+ *
23
+ * Quem traduz este par para o `where` do banco é o `resolveDateRange` /
24
+ * `dateRangeWhere` (`./date-range`).
25
+ */
26
+
27
+ /**
28
+ * O admin manda `?from=` quando o usuário **limpa** o campo. O `@IsOptional()`
29
+ * só pula `null`/`undefined`, então sem isto o campo limpo viraria 400 — uma
30
+ * regressão de tela causada por um parâmetro que nem deveria existir. O
31
+ * `@Transform` roda no `plainToInstance` do `ValidationPipe`, antes do
32
+ * `validate`, então a string vazia nunca chega ao validador.
33
+ */
34
+ const blankToUndefined = ({ value }: { value: unknown }) => {
35
+ const raw = typeof value === 'string' ? value.trim() : value;
36
+
37
+ return raw === '' || raw === null ? undefined : raw;
38
+ };
39
+
40
+ export class DateRangeQueryDTO {
41
+ /** Primeiro dia do recorte, inclusive. `yyyy-MM-dd`. */
42
+ @IsOptional()
43
+ @Transform(blankToUndefined)
44
+ @IsDateString({}, { message: 'from must be a date in the yyyy-MM-dd format' })
45
+ from?: string;
46
+
47
+ /**
48
+ * Último dia do recorte, **inclusive** — é assim que o usuário lê o
49
+ * calendário. Quem converte para o `< to+1d` que o banco precisa é o
50
+ * `resolveDateRange`.
51
+ */
52
+ @IsOptional()
53
+ @Transform(blankToUndefined)
54
+ @IsDateString({}, { message: 'to must be a date in the yyyy-MM-dd format' })
55
+ to?: string;
56
+ }
@@ -0,0 +1,175 @@
1
+ import { addIsoDays, dateRangeWhere, resolveDateRange } from './date-range';
2
+
3
+ describe('resolveDateRange', () => {
4
+ it('devolve null quando não há período', () => {
5
+ expect(resolveDateRange()).toBeNull();
6
+ expect(resolveDateRange('', '')).toBeNull();
7
+ expect(resolveDateRange(null, null)).toBeNull();
8
+ });
9
+
10
+ it('só com `from`, limita apenas o início', () => {
11
+ const range = resolveDateRange('2026-08-01')!;
12
+
13
+ expect(range.gte).toEqual(new Date('2026-08-01T00:00:00.000Z'));
14
+ expect(range.lt).toBeUndefined();
15
+ });
16
+
17
+ it('só com `to`, limita apenas o fim', () => {
18
+ const range = resolveDateRange(undefined, '2026-08-31')!;
19
+
20
+ expect(range.lt).toEqual(new Date('2026-09-01T00:00:00.000Z'));
21
+ expect(range.gte).toBeUndefined();
22
+ });
23
+
24
+ /**
25
+ * O caso que os três serviços erravam: com `lte` + `new Date(to)` o dia 31
26
+ * inteiro ficava de fora, porque `'2026-08-31'` vira o INSTANTE
27
+ * `2026-08-31T00:00:00Z`.
28
+ */
29
+ it('inclui o dia final inteiro', () => {
30
+ const { lt } = resolveDateRange('2026-08-01', '2026-08-31')!;
31
+
32
+ expect(lt).toEqual(new Date('2026-09-01T00:00:00.000Z'));
33
+ expect(new Date('2026-08-31T23:59:59.999Z') < lt!).toBe(true);
34
+ expect(new Date('2026-09-01T00:00:00.000Z') < lt!).toBe(false);
35
+ });
36
+
37
+ it('atravessa a virada do mês e do ano', () => {
38
+ expect(resolveDateRange('2026-12-31', '2026-12-31')!.lt).toEqual(
39
+ new Date('2027-01-01T00:00:00.000Z'),
40
+ );
41
+ });
42
+
43
+ it('cobre o 29 de fevereiro em ano bissexto', () => {
44
+ expect(resolveDateRange('2028-02-28', '2028-02-29')!.lt).toEqual(
45
+ new Date('2028-03-01T00:00:00.000Z'),
46
+ );
47
+ });
48
+
49
+ it('inverte o período digitado de trás pra frente', () => {
50
+ expect(resolveDateRange('2026-08-31', '2026-08-01')).toEqual(
51
+ resolveDateRange('2026-08-01', '2026-08-31'),
52
+ );
53
+ });
54
+
55
+ it('trata data inválida como ausente, sem estourar', () => {
56
+ expect(resolveDateRange('31/08/2026', '2026-08-31')!.gte).toBeUndefined();
57
+ expect(resolveDateRange('2026-13-01')).toBeNull();
58
+ expect(resolveDateRange('2026-02-31')).toBeNull();
59
+ expect(resolveDateRange('ontem')).toBeNull();
60
+ });
61
+
62
+ it('aceita ISO completo e ignora a hora', () => {
63
+ expect(
64
+ resolveDateRange('2026-08-01T13:45:00.000Z', '2026-08-31T09:00:00Z'),
65
+ ).toEqual(resolveDateRange('2026-08-01', '2026-08-31'));
66
+ });
67
+
68
+ it('não limita o fim a agora — período no futuro continua aberto', () => {
69
+ // Contrato vigente, reunião agendada e assinatura a vencer dependem disso.
70
+ const { lt } = resolveDateRange('2099-01-01', '2099-12-31')!;
71
+
72
+ expect(lt).toEqual(new Date('2100-01-01T00:00:00.000Z'));
73
+ expect(lt!.getTime()).toBeGreaterThan(Date.now());
74
+ });
75
+
76
+ it('expõe as strings que o SQL cru precisa', () => {
77
+ const range = resolveDateRange('2026-08-01', '2026-08-31')!;
78
+
79
+ expect(range.fromIso).toBe('2026-08-01');
80
+ expect(range.toExclusiveIso).toBe('2026-09-01');
81
+ });
82
+ });
83
+
84
+ describe('resolveDateRange — fuso', () => {
85
+ it('desloca as bordas para o fuso pedido', () => {
86
+ // Em São Paulo (UTC-3) o dia civil começa às 03:00 UTC.
87
+ const range = resolveDateRange('2026-08-01', '2026-08-31', {
88
+ timezone: 'America/Sao_Paulo',
89
+ })!;
90
+
91
+ expect(range.gte).toEqual(new Date('2026-08-01T03:00:00.000Z'));
92
+ expect(range.lt).toEqual(new Date('2026-09-01T03:00:00.000Z'));
93
+ });
94
+
95
+ /**
96
+ * A armadilha da coluna `@db.Date`: o Prisma manda o parâmetro como `DATE` e
97
+ * o trunca pela leitura UTC. Meia-noite de 01/08 em Tóquio é
98
+ * `2026-07-31T15:00Z`, que truncaria para 31/07 e derrubaria um dia inteiro
99
+ * da consulta, sem erro nenhum. Por isso `dateOnly` ignora o fuso.
100
+ */
101
+ it('mantém `dateOnly` em UTC puro, mesmo com fuso a leste', () => {
102
+ const range = resolveDateRange('2026-08-01', '2026-08-31', {
103
+ timezone: 'Asia/Tokyo',
104
+ })!;
105
+
106
+ expect(range.gte).toEqual(new Date('2026-07-31T15:00:00.000Z'));
107
+ expect(range.dateOnly.gte).toEqual(new Date('2026-08-01T00:00:00.000Z'));
108
+ expect(range.dateOnly.lt).toEqual(new Date('2026-09-01T00:00:00.000Z'));
109
+ });
110
+
111
+ it('acerta a borda na virada do horário de verão', () => {
112
+ // Lisboa entra no horário de verão em 29/03/2026: antes UTC+0, depois +1.
113
+ const range = resolveDateRange('2026-03-28', '2026-03-30', {
114
+ timezone: 'Europe/Lisbon',
115
+ })!;
116
+
117
+ expect(range.gte).toEqual(new Date('2026-03-28T00:00:00.000Z'));
118
+ expect(range.lt).toEqual(new Date('2026-03-30T23:00:00.000Z'));
119
+ });
120
+
121
+ it('cai no UTC quando o fuso é desconhecido', () => {
122
+ expect(
123
+ resolveDateRange('2026-08-01', '2026-08-31', { timezone: 'Nao/Existe' }),
124
+ ).toEqual(resolveDateRange('2026-08-01', '2026-08-31'));
125
+ });
126
+ });
127
+
128
+ describe('addIsoDays', () => {
129
+ it('soma dias de calendário', () => {
130
+ expect(addIsoDays('2026-08-31', 1)).toBe('2026-09-01');
131
+ expect(addIsoDays('2026-12-31', 1)).toBe('2027-01-01');
132
+ expect(addIsoDays('2028-02-28', 1)).toBe('2028-02-29');
133
+ expect(addIsoDays('2026-09-01', -1)).toBe('2026-08-31');
134
+ });
135
+ });
136
+
137
+ describe('dateRangeWhere', () => {
138
+ it('devolve {} sem período, pra espalhar ser sempre seguro', () => {
139
+ expect(dateRangeWhere('created_at')).toEqual({});
140
+ expect(dateRangeWhere('created_at', '', '')).toEqual({});
141
+ expect({ deleted_at: null, ...dateRangeWhere('created_at') }).toEqual({
142
+ deleted_at: null,
143
+ });
144
+ });
145
+
146
+ it('monta o fragmento do Prisma', () => {
147
+ expect(dateRangeWhere('created_at', '2026-08-01', '2026-08-31')).toEqual({
148
+ created_at: {
149
+ gte: new Date('2026-08-01T00:00:00.000Z'),
150
+ lt: new Date('2026-09-01T00:00:00.000Z'),
151
+ },
152
+ });
153
+ });
154
+
155
+ it('usa as bordas UTC puras para coluna de data', () => {
156
+ expect(
157
+ dateRangeWhere('meeting_date', '2026-08-01', '2026-08-31', {
158
+ dateOnly: true,
159
+ timezone: 'America/Sao_Paulo',
160
+ }),
161
+ ).toEqual({
162
+ meeting_date: {
163
+ gte: new Date('2026-08-01T00:00:00.000Z'),
164
+ lt: new Date('2026-09-01T00:00:00.000Z'),
165
+ },
166
+ });
167
+ });
168
+
169
+ it('omite a chave ausente em vez de pô-la como undefined', () => {
170
+ const where = dateRangeWhere('created_at', '2026-08-01');
171
+
172
+ expect(Object.keys(where.created_at)).toEqual(['gte']);
173
+ expect('lt' in where.created_at).toBe(false);
174
+ });
175
+ });