@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
@@ -14,22 +14,62 @@ export declare class SessionService {
14
14
  private readonly user;
15
15
  private readonly paginationService;
16
16
  private readonly logger;
17
+ /**
18
+ * Janela em que o refresh token ANTERIOR continua sendo aceito depois de uma
19
+ * rotacao.
20
+ *
21
+ * Sem ela a rotacao e um handoff sem tolerancia: se a resposta do
22
+ * `/auth/refresh` se perde no caminho de volta — rede caindo, aba suspensa,
23
+ * pod reciclado no meio de um rollout — o servidor ja girou e o cliente fica
24
+ * com um token que nao vale mais. Uma sessao valida de 30 dias morre por um
25
+ * soluco de rede, e o unico rastro e um 401 solto. A janela tambem absorve
26
+ * duas abas renovando ao mesmo tempo.
27
+ *
28
+ * Curta de proposito: ela existe para cobrir a corrida e a resposta perdida,
29
+ * nao para prolongar a vida do token.
30
+ */
31
+ private static readonly REFRESH_GRACE_MS;
32
+ /**
33
+ * Sessao aberta por um cliente OAuth externo vive menos que a de login: o
34
+ * refresh token esta com um terceiro. Vale na criacao E na renovacao — sem
35
+ * reaplicar aqui, a primeira renovacao devolvia a sessao aos 30 dias globais e
36
+ * o limite virava decoracao.
37
+ */
38
+ static readonly CONNECTOR_SESSION_TTL_MINUTES: number;
39
+ /**
40
+ * Tentativas de rotacao por chamada. A segunda cobre o caso de outra
41
+ * requisicao ter girado a sessao entre a leitura e o compare-and-swap.
42
+ */
43
+ private static readonly REFRESH_ROTATION_ATTEMPTS;
17
44
  constructor(prisma: PrismaService, security: SecurityService, setting: SettingService, token: TokenService, http: HttpService, user: UserService, paginationService: PaginationService);
18
- create(locale: string, userId: number, ipAddress: string, userAgent: string, browserId?: string | null): Promise<{
45
+ /**
46
+ * `oauth` marca a sessao como pertencente a um cliente OAuth externo. Vem
47
+ * preenchido so pela troca do authorization code quando o cliente pediu um
48
+ * `resource`; o login normal continua chamando sem ele e nada muda.
49
+ */
50
+ create(locale: string, userId: number, ipAddress: string, userAgent: string, browserId?: string | null, oauth?: {
51
+ audience: string;
52
+ clientId: string;
53
+ ttlMinutes?: number;
54
+ }): Promise<{
19
55
  token: string;
20
56
  session: {
21
57
  id: number;
22
58
  user_id: number;
23
59
  user_agent: string;
24
- impersonator_user_id: number | null;
25
60
  created_at: Date;
61
+ impersonator_user_id: number | null;
26
62
  updated_at: Date;
27
63
  hash: string;
28
- browser_id: string | null;
29
64
  ip_address: string;
30
65
  revoked_at: Date | null;
31
66
  expires_at: Date;
67
+ browser_id: string | null;
32
68
  impersonation_reason: string | null;
69
+ previous_hash: string | null;
70
+ previous_hash_expires_at: Date | null;
71
+ audience: string | null;
72
+ oauth_client_id: string | null;
33
73
  };
34
74
  }>;
35
75
  /**
@@ -48,15 +88,19 @@ export declare class SessionService {
48
88
  id: number;
49
89
  user_id: number;
50
90
  user_agent: string;
51
- impersonator_user_id: number | null;
52
91
  created_at: Date;
92
+ impersonator_user_id: number | null;
53
93
  updated_at: Date;
54
94
  hash: string;
55
- browser_id: string | null;
56
95
  ip_address: string;
57
96
  revoked_at: Date | null;
58
97
  expires_at: Date;
98
+ browser_id: string | null;
59
99
  impersonation_reason: string | null;
100
+ previous_hash: string | null;
101
+ previous_hash_expires_at: Date | null;
102
+ audience: string | null;
103
+ oauth_client_id: string | null;
60
104
  }>;
61
105
  /**
62
106
  * Anexa `impersonator: { id, name }` as sessoes simuladas. Nao ha relacao
@@ -65,23 +109,75 @@ export declare class SessionService {
65
109
  * `UserService.listUserChangeLogs` com os atores.
66
110
  */
67
111
  private attachImpersonators;
112
+ /**
113
+ * Anexa `oauth_client: { client_id, name }` as sessoes abertas por um cliente
114
+ * OAuth externo. Mesmo padrao de `attachImpersonators`, e pela mesma razao:
115
+ * `oauth_client_id` e VARCHAR puro, sem FK.
116
+ *
117
+ * Existe porque sem o nome a tela de seguranca do usuario fica ILEGIVEL para
118
+ * esse caso: um conector fala com a API a partir da nuvem do fornecedor, entao
119
+ * a linha aparece com user agent que o ua-parser nao reconhece
120
+ * (`python-httpx/0.28.1`), sem dispositivo, e geolocalizada no pais dele. Para
121
+ * quem esta no Brasil, e indistinguivel de uma conta invadida.
122
+ */
123
+ private attachOAuthClients;
124
+ /**
125
+ * Gira o refresh token PRESERVANDO a identidade da sessao.
126
+ *
127
+ * A versao anterior revogava a linha e criava outra, com `id` novo. Como
128
+ * `TokenService.verify` valida a sessao no banco a cada request e recusa
129
+ * qualquer access token cuja sessao esteja revogada, o instante do refresh
130
+ * matava todos os access tokens em voo — na hora, e nao no `exp`. Numa tela
131
+ * que dispara ~10 chamadas em paralelo isso virava reacao em cadeia: cada 401
132
+ * disparava outro refresh, cada refresh matava os tokens dos outros. Nos logs
133
+ * de producao de 24/08 foram doze sessoes giradas em 18 segundos para o mesmo
134
+ * usuario, terminando em `Refresh rejected` e logout.
135
+ *
136
+ * Com o `id` estavel, o access token que ja saiu continua valido ate o proprio
137
+ * `exp`, e a rotacao deixa de ser um evento observavel pelo resto do app. De
138
+ * quebra a tabela para de crescer uma linha a cada 15 minutos por dispositivo.
139
+ */
68
140
  refresh(locale: string, refreshToken: string, ipAddress: string, userAgent: string, browserId?: string | null): Promise<{
69
141
  token: string;
70
142
  session: {
71
143
  id: number;
72
144
  user_id: number;
73
- user_agent: string;
74
- impersonator_user_id: number | null;
75
- created_at: Date;
76
- updated_at: Date;
77
- hash: string;
78
- browser_id: string | null;
79
145
  ip_address: string;
80
- revoked_at: Date | null;
146
+ user_agent: string;
147
+ browser_id: string;
81
148
  expires_at: Date;
82
- impersonation_reason: string | null;
149
+ audience: string;
150
+ oauth_client_id: string;
83
151
  };
84
152
  }>;
153
+ /**
154
+ * Casa o refresh token apresentado com a sessao: pelo hash corrente, ou pelo
155
+ * anterior enquanto a janela de graca estiver aberta.
156
+ *
157
+ * O limite pela janela e o que impede um token antigo qualquer de ressuscitar
158
+ * uma sessao — so o imediatamente anterior, e so por
159
+ * `REFRESH_GRACE_MS`, continua servindo.
160
+ */
161
+ /**
162
+ * Le a sessao de um refresh token SEM rotacionar nada.
163
+ *
164
+ * Existe porque `refresh()` encontra e gira na mesma operacao: quem precisa
165
+ * decidir se aceita a renovacao (o client confere? o resource confere? a sessao
166
+ * e de conector?) so podia fazer isso depois do compare-and-swap ja commitado —
167
+ * e uma recusa deixava o cliente com um token morto em 30 segundos, sem nunca
168
+ * receber o substituto. Validar antes e a diferenca entre negar um pedido e
169
+ * destruir a sessao.
170
+ */
171
+ peekByRefreshToken(refreshToken: string): Promise<{
172
+ id: number;
173
+ user_id: number;
174
+ impersonator_user_id: number;
175
+ revoked_at: Date;
176
+ expires_at: Date;
177
+ audience: string;
178
+ oauth_client_id: string;
179
+ }>;
180
+ private refreshTokenWhere;
85
181
  deleteRefreshTokenCookie(res: any, refreshToken: string): Promise<{
86
182
  count: number;
87
183
  userId: number;
@@ -108,15 +204,19 @@ export declare class SessionService {
108
204
  id: number;
109
205
  user_id: number;
110
206
  user_agent: string;
111
- impersonator_user_id: number | null;
112
207
  created_at: Date;
208
+ impersonator_user_id: number | null;
113
209
  updated_at: Date;
114
210
  hash: string;
115
- browser_id: string | null;
116
211
  ip_address: string;
117
212
  revoked_at: Date | null;
118
213
  expires_at: Date;
214
+ browser_id: string | null;
119
215
  impersonation_reason: string | null;
216
+ previous_hash: string | null;
217
+ previous_hash_expires_at: Date | null;
218
+ audience: string | null;
219
+ oauth_client_id: string | null;
120
220
  }>;
121
221
  /**
122
222
  * Enforce maximum concurrent sessions limit for a user.
@@ -128,6 +228,9 @@ export declare class SessionService {
128
228
  * @param isRotation - When true, the calling flow is replacing an existing session (refresh),
129
229
  * not adding a new one, so no extra slot needs to be freed.
130
230
  * @param currentBrowserId - The browser_id of the session being created/refreshed.
231
+ * @param keepSessionId - Session that must survive: its whole browser slot is
232
+ * excluded from eviction. Passed by the refresh flow, so renewing a live
233
+ * session can never revoke the very session being renewed.
131
234
  */
132
235
  private enforceSessionLimit;
133
236
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session.service.d.ts","sourceRoot":"","sources":["../../src/session/session.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAanD,qBACa,cAAc;IAIvB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAfpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;gBAGhD,MAAM,EAAE,aAAa,EAErB,QAAQ,EAAE,eAAe,EAEhB,OAAO,EAAE,cAAc,EAEvB,KAAK,EAAE,YAAY,EAEnB,IAAI,EAAE,WAAW,EAEjB,IAAI,EAAE,WAAW,EAEjB,iBAAiB,EAAE,iBAAiB;IAGjD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;IAuC5G;;;;;;;;;;;OAWG;IACG,mBAAmB,CACvB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;IAsBxB;;;;;OAKG;YACW,mBAAmB;IAwB3B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;IAqG7G,wBAAwB,CAAC,GAAG,KAAA,EAAE,YAAY,EAAE,MAAM;;;;IAkClD,eAAe,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;IAmD/E,qBAAqB,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;YAmD7E,YAAY;YAmBZ,mBAAmB;IAQ3B,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAexD,iBAAiB,CAAC,MAAM,EAAE,MAAM;IAIhC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;IA0BzE;;;;;;;;;;OAUG;YACW,mBAAmB;CAmDlC"}
1
+ {"version":3,"file":"session.service.d.ts","sourceRoot":"","sources":["../../src/session/session.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAanD,qBACa,cAAc;IAkCvB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,QAAQ;IAEhB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IA7CpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAElD;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,6BAA6B,SAAe;IAE5D;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAK;gBAG5C,MAAM,EAAE,aAAa,EAErB,QAAQ,EAAE,eAAe,EAEhB,OAAO,EAAE,cAAc,EAEvB,KAAK,EAAE,YAAY,EAEnB,IAAI,EAAE,WAAW,EAEjB,IAAI,EAAE,WAAW,EAEjB,iBAAiB,EAAE,iBAAiB;IAGvD;;;;OAIG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EACzB,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;;;;IAwDrE;;;;;;;;;;;OAWG;IACG,mBAAmB,CACvB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;IAsBxB;;;;;OAKG;YACW,mBAAmB;IAwBjC;;;;;;;;;;OAUG;YACW,kBAAkB;IAgChC;;;;;;;;;;;;;;;OAeG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;IAiHnH;;;;;;;OAOG;IACH;;;;;;;;;OASG;IACG,kBAAkB,CAAC,YAAY,EAAE,MAAM;;;;;;;;;IAmB7C,OAAO,CAAC,iBAAiB;IASnB,wBAAwB,CAAC,GAAG,KAAA,EAAE,YAAY,EAAE,MAAM;;;;IAiClD,eAAe,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;IAmD/E,qBAAqB,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;YAmD7E,YAAY;YAmBZ,mBAAmB;IAQ3B,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAexD,iBAAiB,CAAC,MAAM,EAAE,MAAM;IAIhC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;IA0BzE;;;;;;;;;;;;;OAaG;YACW,mBAAmB;CAuElC"}
@@ -46,7 +46,13 @@ let SessionService = SessionService_1 = class SessionService {
46
46
  this.paginationService = paginationService;
47
47
  this.logger = new common_1.Logger(SessionService_1.name);
48
48
  }
49
- async create(locale, userId, ipAddress, userAgent, browserId) {
49
+ /**
50
+ * `oauth` marca a sessao como pertencente a um cliente OAuth externo. Vem
51
+ * preenchido so pela troca do authorization code quando o cliente pediu um
52
+ * `resource`; o login normal continua chamando sem ele e nada muda.
53
+ */
54
+ async create(locale, userId, ipAddress, userAgent, browserId, oauth) {
55
+ var _a, _b;
50
56
  if (!userId) {
51
57
  throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('session.userIdRequired', locale, 'User ID is required to create a session.'));
52
58
  }
@@ -63,17 +69,31 @@ let SessionService = SessionService_1 = class SessionService {
63
69
  const token = await this.token.createOpaqueToken();
64
70
  const hash = this.security.hashWithPepper(token);
65
71
  const maxSessions = Number(settings['max-concurrent-sessions']) || 0;
66
- if (maxSessions > 0) {
72
+ // E pela mesma razao a sessao de conector nao DISPARA o despejo ao nascer.
73
+ // `createImpersonation` ja se isenta assim; aqui o efeito seria o usuario
74
+ // perder o celular por ter autorizado um app.
75
+ if (maxSessions > 0 && !oauth) {
67
76
  await this.enforceSessionLimit(userId, maxSessions, false, browserId);
68
77
  }
78
+ // Sessao de conector vive menos que a de login. Nao e simetria estetica: o
79
+ // refresh token esta com um terceiro, e 30 dias de janela para um segredo que
80
+ // saiu do nosso dominio e generoso demais.
81
+ //
82
+ // `||` e nao `??` em toda a cadeia: `Number(undefined)` e NaN, que passa
83
+ // direto por `??` e produziria um expires_at invalido.
84
+ const ttlMinutes = (oauth === null || oauth === void 0 ? void 0 : oauth.ttlMinutes) ||
85
+ Number(settings['refresh-token-expiration-minutes']) ||
86
+ 43200;
69
87
  const session = await this.prisma.user_session.create({
70
88
  data: {
71
89
  user_id: userId,
72
90
  ip_address: ipAddress,
73
91
  user_agent: userAgent,
74
- expires_at: new Date(Date.now() + ((settings['refresh-token-expiration-minutes'] || 43200) * 60 * 1000)),
92
+ expires_at: new Date(Date.now() + ttlMinutes * 60 * 1000),
75
93
  hash,
76
94
  browser_id: browserId !== null && browserId !== void 0 ? browserId : null,
95
+ audience: (_a = oauth === null || oauth === void 0 ? void 0 : oauth.audience) !== null && _a !== void 0 ? _a : null,
96
+ oauth_client_id: (_b = oauth === null || oauth === void 0 ? void 0 : oauth.clientId) !== null && _b !== void 0 ? _b : null,
77
97
  },
78
98
  });
79
99
  return { token, session };
@@ -131,88 +151,197 @@ let SessionService = SessionService_1 = class SessionService {
131
151
  : null }));
132
152
  });
133
153
  }
154
+ /**
155
+ * Anexa `oauth_client: { client_id, name }` as sessoes abertas por um cliente
156
+ * OAuth externo. Mesmo padrao de `attachImpersonators`, e pela mesma razao:
157
+ * `oauth_client_id` e VARCHAR puro, sem FK.
158
+ *
159
+ * Existe porque sem o nome a tela de seguranca do usuario fica ILEGIVEL para
160
+ * esse caso: um conector fala com a API a partir da nuvem do fornecedor, entao
161
+ * a linha aparece com user agent que o ua-parser nao reconhece
162
+ * (`python-httpx/0.28.1`), sem dispositivo, e geolocalizada no pais dele. Para
163
+ * quem esta no Brasil, e indistinguivel de uma conta invadida.
164
+ */
165
+ async attachOAuthClients(rows) {
166
+ const ids = Array.from(new Set(rows
167
+ .map((row) => row.oauth_client_id)
168
+ .filter((id) => typeof id === 'string' && id.length > 0)));
169
+ if (!ids.length) {
170
+ return rows.map((row) => (Object.assign(Object.assign({}, row), { oauth_client: null })));
171
+ }
172
+ const clients = await this.prisma.oauth_app_client.findMany({
173
+ where: { client_id: { in: ids } },
174
+ select: { client_id: true, name: true },
175
+ });
176
+ const byId = new Map(clients.map((client) => [client.client_id, client]));
177
+ return rows.map((row) => {
178
+ var _a;
179
+ return (Object.assign(Object.assign({}, row), { oauth_client: row.oauth_client_id
180
+ ? // Client removido do registro ainda tem sessao viva: cai no proprio
181
+ // slug, que e melhor que sumir com a informacao.
182
+ ((_a = byId.get(row.oauth_client_id)) !== null && _a !== void 0 ? _a : {
183
+ client_id: row.oauth_client_id,
184
+ name: row.oauth_client_id,
185
+ })
186
+ : null }));
187
+ });
188
+ }
189
+ /**
190
+ * Gira o refresh token PRESERVANDO a identidade da sessao.
191
+ *
192
+ * A versao anterior revogava a linha e criava outra, com `id` novo. Como
193
+ * `TokenService.verify` valida a sessao no banco a cada request e recusa
194
+ * qualquer access token cuja sessao esteja revogada, o instante do refresh
195
+ * matava todos os access tokens em voo — na hora, e nao no `exp`. Numa tela
196
+ * que dispara ~10 chamadas em paralelo isso virava reacao em cadeia: cada 401
197
+ * disparava outro refresh, cada refresh matava os tokens dos outros. Nos logs
198
+ * de producao de 24/08 foram doze sessoes giradas em 18 segundos para o mesmo
199
+ * usuario, terminando em `Refresh rejected` e logout.
200
+ *
201
+ * Com o `id` estavel, o access token que ja saiu continua valido ate o proprio
202
+ * `exp`, e a rotacao deixa de ser um evento observavel pelo resto do app. De
203
+ * quebra a tabela para de crescer uma linha a cada 15 minutos por dispositivo.
204
+ */
134
205
  async refresh(locale, refreshToken, ipAddress, userAgent, browserId) {
206
+ var _a, _b, _c, _d, _e, _f;
135
207
  if (!refreshToken) {
136
208
  throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
137
209
  }
138
210
  const hash = this.security.hashWithPepper(refreshToken);
139
- const rawSession = await this.prisma.user_session.findFirst({
140
- where: { hash },
141
- 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 },
142
- });
143
- if (!rawSession) {
144
- this.logger.warn(`[SessionRefresh] Refresh rejected: hash prefix ${hash.slice(0, 8)} not found in DB`);
145
- throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
146
- }
147
- if (rawSession.revoked_at !== null) {
148
- 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)}`);
149
- throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
150
- }
151
- if (rawSession.expires_at <= new Date()) {
152
- 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)}`);
153
- throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
154
- }
155
- // Simulacao de acesso e nao renovavel. `createImpersonation` ja descarta o
156
- // token opaco, entao chegar aqui significa que alguem obteve o segredo por
157
- // outro caminho — e renovar transformaria a janela de 30 minutos numa sessao
158
- // normal de 30 dias, sem a marca de simulado.
159
- if (rawSession.impersonator_user_id !== null) {
160
- this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} is an impersonation session`);
161
- throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
162
- }
163
- const session = {
164
- id: rawSession.id,
165
- user_id: rawSession.user_id,
166
- ip_address: rawSession.ip_address,
167
- user_agent: rawSession.user_agent,
168
- browser_id: rawSession.browser_id,
169
- };
170
211
  const settings = await this.setting.getSettingValues([
171
212
  'refresh-token-expiration-minutes',
172
213
  'max-concurrent-sessions',
173
214
  ]);
174
215
  const maxSessions = Number(settings['max-concurrent-sessions']) || 0;
175
- if (maxSessions > 0) {
176
- await this.enforceSessionLimit(session.user_id, maxSessions, true, browserId);
177
- }
178
- const nextRefreshToken = await this.token.createOpaqueToken();
179
- const nextHash = this.security.hashWithPepper(nextRefreshToken);
180
- const expiresAt = new Date(Date.now() + ((settings['refresh-token-expiration-minutes'] || 43200) * 60 * 1000));
181
- const nextIpAddress = (ipAddress === null || ipAddress === void 0 ? void 0 : ipAddress.trim()) || session.ip_address || 'unknown';
182
- const nextUserAgent = (userAgent === null || userAgent === void 0 ? void 0 : userAgent.trim()) || session.user_agent || 'unknown';
183
- this.logger.debug(`[SessionRefresh] Starting rotation userId=${session.user_id} oldSessionId=${session.id} ip=${nextIpAddress}`);
184
- const txStart = Date.now();
185
- const { updateResult, newSession } = await this.prisma.$transaction(async (tx) => {
186
- var _a, _b;
187
- const updateResult = await tx.user_session.updateMany({
216
+ const ttlMinutes = Number(settings['refresh-token-expiration-minutes']) || 43200;
217
+ for (let attempt = 1; attempt <= SessionService_1.REFRESH_ROTATION_ATTEMPTS; attempt++) {
218
+ const rawSession = await this.prisma.user_session.findFirst({
219
+ where: this.refreshTokenWhere(hash),
220
+ 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 },
221
+ });
222
+ if (!rawSession) {
223
+ this.logger.warn(`[SessionRefresh] Refresh rejected: hash prefix ${hash.slice(0, 8)} not found in DB`);
224
+ throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
225
+ }
226
+ if (rawSession.revoked_at !== null) {
227
+ 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)}`);
228
+ throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
229
+ }
230
+ if (rawSession.expires_at <= new Date()) {
231
+ 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)}`);
232
+ throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
233
+ }
234
+ // Simulacao de acesso e nao renovavel. `createImpersonation` ja descarta o
235
+ // token opaco, entao chegar aqui significa que alguem obteve o segredo por
236
+ // outro caminho — e renovar transformaria a janela de 30 minutos numa sessao
237
+ // normal de 30 dias, sem a marca de simulado.
238
+ if (rawSession.impersonator_user_id !== null) {
239
+ this.logger.warn(`[SessionRefresh] Refresh rejected: sessionId=${rawSession.id} userId=${rawSession.user_id} is an impersonation session`);
240
+ throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
241
+ }
242
+ const nextRefreshToken = await this.token.createOpaqueToken();
243
+ const nextHash = this.security.hashWithPepper(nextRefreshToken);
244
+ const now = Date.now();
245
+ // Sessao de conector nao volta aos 30 dias globais so por ter sido
246
+ // renovada — o TTL curto e a propriedade que a distingue.
247
+ const effectiveTtl = rawSession.audience
248
+ ? Math.min(ttlMinutes, SessionService_1.CONNECTOR_SESSION_TTL_MINUTES)
249
+ : ttlMinutes;
250
+ const expiresAt = new Date(now + effectiveTtl * 60 * 1000);
251
+ const nextIpAddress = (ipAddress === null || ipAddress === void 0 ? void 0 : ipAddress.trim()) || rawSession.ip_address || 'unknown';
252
+ const nextUserAgent = (userAgent === null || userAgent === void 0 ? void 0 : userAgent.trim()) || rawSession.user_agent || 'unknown';
253
+ // Compare-and-swap pelo hash corrente, na MESMA linha. Se outra requisicao
254
+ // girou primeiro, `count` volta 0 e a proxima volta le o hash novo — em vez
255
+ // de devolver 401 para o perdedor da corrida, como antes.
256
+ const updateResult = await this.prisma.user_session.updateMany({
188
257
  where: {
189
- id: session.id,
258
+ id: rawSession.id,
190
259
  revoked_at: null,
260
+ hash: rawSession.hash,
191
261
  },
192
262
  data: {
193
- revoked_at: new Date(),
263
+ hash: nextHash,
264
+ previous_hash: rawSession.hash,
265
+ previous_hash_expires_at: new Date(now + SessionService_1.REFRESH_GRACE_MS),
266
+ expires_at: expiresAt,
267
+ ip_address: nextIpAddress,
268
+ user_agent: nextUserAgent,
269
+ browser_id: (_b = (_a = rawSession.browser_id) !== null && _a !== void 0 ? _a : browserId) !== null && _b !== void 0 ? _b : null,
270
+ updated_at: new Date(),
194
271
  },
195
272
  });
196
- const newSession = await tx.user_session.create({
197
- data: {
198
- user_id: session.user_id,
273
+ if (updateResult.count === 0) {
274
+ this.logger.debug(`[SessionRefresh] Rotation lost the CAS sessionId=${rawSession.id} userId=${rawSession.user_id} attempt=${attempt}`);
275
+ continue;
276
+ }
277
+ // Depois da rotacao, nunca antes. Rodando antes, o limite podia revogar a
278
+ // propria sessao que estava sendo renovada e o CAS falhava sozinho. E
279
+ // `keepSessionId` garante que renovar nunca despeja quem esta renovando.
280
+ if (maxSessions > 0) {
281
+ await this.enforceSessionLimit(rawSession.user_id, maxSessions, true, browserId, rawSession.id);
282
+ }
283
+ this.logger.debug(`[SessionRefresh] Rotation successful userId=${rawSession.user_id} sessionId=${rawSession.id} durationMs=${Date.now() - now}`);
284
+ return {
285
+ token: nextRefreshToken,
286
+ session: {
287
+ id: rawSession.id,
288
+ user_id: rawSession.user_id,
199
289
  ip_address: nextIpAddress,
200
290
  user_agent: nextUserAgent,
291
+ browser_id: (_d = (_c = rawSession.browser_id) !== null && _c !== void 0 ? _c : browserId) !== null && _d !== void 0 ? _d : null,
201
292
  expires_at: expiresAt,
202
- hash: nextHash,
203
- browser_id: (_b = (_a = session.browser_id) !== null && _a !== void 0 ? _a : browserId) !== null && _b !== void 0 ? _b : null,
293
+ // Quem renova precisa saber que esta renovando uma sessao de conector:
294
+ // e dai que sai o `aud` do proximo access token. Sem isso a rotacao
295
+ // devolveria um token de sessao comum e desfaria o vinculo.
296
+ audience: (_e = rawSession.audience) !== null && _e !== void 0 ? _e : null,
297
+ oauth_client_id: (_f = rawSession.oauth_client_id) !== null && _f !== void 0 ? _f : null,
204
298
  },
205
- });
206
- return { updateResult, newSession };
207
- });
208
- if (updateResult.count === 0) {
209
- this.logger.warn(`[SessionRefresh] Race condition detected: userId=${session.user_id} oldSessionId=${session.id} already rotated by another request (durationMs=${Date.now() - txStart})`);
210
- throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
299
+ };
211
300
  }
212
- this.logger.debug(`[SessionRefresh] Rotation successful userId=${session.user_id} oldSessionId=${session.id} newSessionId=${newSession.id} durationMs=${Date.now() - txStart}`);
301
+ this.logger.warn(`[SessionRefresh] Rotation gave up after ${SessionService_1.REFRESH_ROTATION_ATTEMPTS} attempts: hash prefix ${hash.slice(0, 8)}`);
302
+ throw new common_1.UnauthorizedException((0, api_locale_1.getLocaleText)('accessDenied', locale, 'Access denied.'));
303
+ }
304
+ /**
305
+ * Casa o refresh token apresentado com a sessao: pelo hash corrente, ou pelo
306
+ * anterior enquanto a janela de graca estiver aberta.
307
+ *
308
+ * O limite pela janela e o que impede um token antigo qualquer de ressuscitar
309
+ * uma sessao — so o imediatamente anterior, e so por
310
+ * `REFRESH_GRACE_MS`, continua servindo.
311
+ */
312
+ /**
313
+ * Le a sessao de um refresh token SEM rotacionar nada.
314
+ *
315
+ * Existe porque `refresh()` encontra e gira na mesma operacao: quem precisa
316
+ * decidir se aceita a renovacao (o client confere? o resource confere? a sessao
317
+ * e de conector?) so podia fazer isso depois do compare-and-swap ja commitado —
318
+ * e uma recusa deixava o cliente com um token morto em 30 segundos, sem nunca
319
+ * receber o substituto. Validar antes e a diferenca entre negar um pedido e
320
+ * destruir a sessao.
321
+ */
322
+ async peekByRefreshToken(refreshToken) {
323
+ if (!refreshToken)
324
+ return null;
325
+ const hash = this.security.hashWithPepper(refreshToken);
326
+ return this.prisma.user_session.findFirst({
327
+ where: this.refreshTokenWhere(hash),
328
+ select: {
329
+ id: true,
330
+ user_id: true,
331
+ revoked_at: true,
332
+ expires_at: true,
333
+ audience: true,
334
+ oauth_client_id: true,
335
+ impersonator_user_id: true,
336
+ },
337
+ });
338
+ }
339
+ refreshTokenWhere(hash) {
213
340
  return {
214
- token: nextRefreshToken,
215
- session: newSession,
341
+ OR: [
342
+ { hash },
343
+ { previous_hash: hash, previous_hash_expires_at: { gt: new Date() } },
344
+ ],
216
345
  };
217
346
  }
218
347
  async deleteRefreshTokenCookie(res, refreshToken) {
@@ -222,20 +351,18 @@ let SessionService = SessionService_1 = class SessionService {
222
351
  return { count: 0, userId: null };
223
352
  }
224
353
  const hash = this.security.hashWithPepper(refreshToken);
354
+ // Aceita tambem o hash anterior dentro da janela de graca: sair da conta com
355
+ // um token que acabou de girar tem de derrubar a sessao de verdade, e nao
356
+ // devolver sucesso deixando-a viva.
357
+ const where = Object.assign({ revoked_at: null }, this.refreshTokenWhere(hash));
225
358
  const session = await this.prisma.user_session.findFirst({
226
- where: {
227
- revoked_at: null,
228
- hash,
229
- },
359
+ where,
230
360
  select: {
231
361
  user_id: true,
232
362
  },
233
363
  });
234
364
  const result = await this.prisma.user_session.updateMany({
235
- where: {
236
- revoked_at: null,
237
- hash,
238
- },
365
+ where,
239
366
  data: {
240
367
  revoked_at: new Date(),
241
368
  },
@@ -277,7 +404,7 @@ let SessionService = SessionService_1 = class SessionService {
277
404
  return Object.assign(Object.assign({}, s), { location });
278
405
  }));
279
406
  return {
280
- data: await this.attachImpersonators(itemsWithLocation),
407
+ data: await this.attachOAuthClients(await this.attachImpersonators(itemsWithLocation)),
281
408
  total: paginate.total || 0,
282
409
  lastPage: Math.ceil((paginate.total || 0) / (paginate.pageSize || 1)),
283
410
  page: (_a = paginate.page) !== null && _a !== void 0 ? _a : 1,
@@ -320,7 +447,7 @@ let SessionService = SessionService_1 = class SessionService {
320
447
  return Object.assign(Object.assign({}, s), { location });
321
448
  }));
322
449
  return {
323
- data: await this.attachImpersonators(itemsWithLocation),
450
+ data: await this.attachOAuthClients(await this.attachImpersonators(itemsWithLocation)),
324
451
  total: paginate.total || 0,
325
452
  lastPage: Math.ceil((paginate.total || 0) / (paginate.pageSize || 1)),
326
453
  page: (_a = paginate.page) !== null && _a !== void 0 ? _a : 1,
@@ -404,8 +531,11 @@ let SessionService = SessionService_1 = class SessionService {
404
531
  * @param isRotation - When true, the calling flow is replacing an existing session (refresh),
405
532
  * not adding a new one, so no extra slot needs to be freed.
406
533
  * @param currentBrowserId - The browser_id of the session being created/refreshed.
534
+ * @param keepSessionId - Session that must survive: its whole browser slot is
535
+ * excluded from eviction. Passed by the refresh flow, so renewing a live
536
+ * session can never revoke the very session being renewed.
407
537
  */
408
- async enforceSessionLimit(userId, maxSessions, isRotation = false, currentBrowserId) {
538
+ async enforceSessionLimit(userId, maxSessions, isRotation = false, currentBrowserId, keepSessionId) {
409
539
  var _a;
410
540
  const activeSessions = await this.prisma.user_session.findMany({
411
541
  where: {
@@ -415,6 +545,11 @@ let SessionService = SessionService_1 = class SessionService {
415
545
  // Simulacao de acesso nao consome slot: ela nasce com browser_id nulo e
416
546
  // seria contada como slot proprio, despejando uma sessao real do alvo.
417
547
  impersonator_user_id: null,
548
+ // Sessao de cliente OAuth externo, pelo mesmo motivo: um cliente MCP nao
549
+ // manda X-Browser-ID, entao cada conexao viraria um slot proprio e
550
+ // derrubaria um dispositivo de verdade do usuario — que so queria ligar o
551
+ // Claude. Conector nao e navegador.
552
+ audience: null,
418
553
  },
419
554
  orderBy: { created_at: 'asc' },
420
555
  select: { id: true, browser_id: true }
@@ -428,6 +563,15 @@ let SessionService = SessionService_1 = class SessionService {
428
563
  }
429
564
  const slots = Array.from(slotMap.values());
430
565
  const currentSlotCount = slots.length;
566
+ // O slot de quem esta renovando nunca entra na fila de despejo: renovar uma
567
+ // sessao viva nao pode derrubar a propria sessao. Sem isto, um usuario com
568
+ // mais slots que o limite era deslogado no proximo refresh — a rotacao
569
+ // revogava a si mesma e o compare-and-swap logo em seguida nao achava a
570
+ // linha.
571
+ const protectedSlot = typeof keepSessionId === 'number'
572
+ ? slots.find((slot) => slot.ids.includes(keepSessionId))
573
+ : undefined;
574
+ const evictable = slots.filter((slot) => slot !== protectedSlot);
431
575
  // A new browser slot is created only when:
432
576
  // - it's not a rotation (rotation keeps the same slot), AND
433
577
  // - the current browser doesn't already have an active slot
@@ -437,10 +581,13 @@ let SessionService = SessionService_1 = class SessionService {
437
581
  this.logger.debug(`[SessionLimit] userId=${userId} slots=${currentSlotCount} maxSessions=${maxSessions} isRotation=${isRotation} browserId=${currentBrowserId !== null && currentBrowserId !== void 0 ? currentBrowserId : 'null'} newSlot=${isNewSlot} toRevoke=${Math.max(0, slotsToRevoke)}`);
438
582
  if (slotsToRevoke > 0) {
439
583
  const sessionIdsToRevoke = [];
440
- for (let i = 0; i < slotsToRevoke; i++) {
441
- sessionIdsToRevoke.push(...slots[i].ids);
584
+ for (let i = 0; i < Math.min(slotsToRevoke, evictable.length); i++) {
585
+ sessionIdsToRevoke.push(...evictable[i].ids);
586
+ }
587
+ if (sessionIdsToRevoke.length === 0) {
588
+ return;
442
589
  }
443
- this.logger.warn(`[SessionLimit] Revoking ${slotsToRevoke} oldest browser slot(s) for userId=${userId}: sessions [${sessionIdsToRevoke.join(',')}]`);
590
+ this.logger.warn(`[SessionLimit] Revoking ${sessionIdsToRevoke.length} session(s) in the oldest browser slot(s) for userId=${userId}: [${sessionIdsToRevoke.join(',')}]`);
444
591
  await this.prisma.user_session.updateMany({
445
592
  where: { id: { in: sessionIdsToRevoke } },
446
593
  data: { revoked_at: new Date() }
@@ -449,6 +596,33 @@ let SessionService = SessionService_1 = class SessionService {
449
596
  }
450
597
  };
451
598
  exports.SessionService = SessionService;
599
+ /**
600
+ * Janela em que o refresh token ANTERIOR continua sendo aceito depois de uma
601
+ * rotacao.
602
+ *
603
+ * Sem ela a rotacao e um handoff sem tolerancia: se a resposta do
604
+ * `/auth/refresh` se perde no caminho de volta — rede caindo, aba suspensa,
605
+ * pod reciclado no meio de um rollout — o servidor ja girou e o cliente fica
606
+ * com um token que nao vale mais. Uma sessao valida de 30 dias morre por um
607
+ * soluco de rede, e o unico rastro e um 401 solto. A janela tambem absorve
608
+ * duas abas renovando ao mesmo tempo.
609
+ *
610
+ * Curta de proposito: ela existe para cobrir a corrida e a resposta perdida,
611
+ * nao para prolongar a vida do token.
612
+ */
613
+ SessionService.REFRESH_GRACE_MS = 30000;
614
+ /**
615
+ * Sessao aberta por um cliente OAuth externo vive menos que a de login: o
616
+ * refresh token esta com um terceiro. Vale na criacao E na renovacao — sem
617
+ * reaplicar aqui, a primeira renovacao devolvia a sessao aos 30 dias globais e
618
+ * o limite virava decoracao.
619
+ */
620
+ SessionService.CONNECTOR_SESSION_TTL_MINUTES = 7 * 24 * 60;
621
+ /**
622
+ * Tentativas de rotacao por chamada. A segunda cobre o caso de outra
623
+ * requisicao ter girado a sessao entre a leitura e o compare-and-swap.
624
+ */
625
+ SessionService.REFRESH_ROTATION_ATTEMPTS = 2;
452
626
  exports.SessionService = SessionService = SessionService_1 = __decorate([
453
627
  (0, common_1.Injectable)(),
454
628
  __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => security_service_1.SecurityService))),