@hed-hog/core 0.0.390 → 0.0.393

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 (528) hide show
  1. package/README.md +39 -0
  2. package/dist/access-log/access-log.controller.d.ts.map +1 -1
  3. package/dist/access-log/access-log.controller.js +1 -1
  4. package/dist/access-log/access-log.controller.js.map +1 -1
  5. package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
  6. package/dist/access-log/access-log.interceptor.js +8 -5
  7. package/dist/access-log/access-log.interceptor.js.map +1 -1
  8. package/dist/access-log/access-log.service.d.ts +4 -0
  9. package/dist/access-log/access-log.service.d.ts.map +1 -1
  10. package/dist/access-log/access-log.service.js +31 -4
  11. package/dist/access-log/access-log.service.js.map +1 -1
  12. package/dist/access-log/dto/query-access-log.dto.d.ts +2 -0
  13. package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -1
  14. package/dist/access-log/dto/query-access-log.dto.js +5 -0
  15. package/dist/access-log/dto/query-access-log.dto.js.map +1 -1
  16. package/dist/ai/ai.controller.d.ts +12 -8
  17. package/dist/ai/ai.controller.d.ts.map +1 -1
  18. package/dist/ai/ai.controller.js +17 -2
  19. package/dist/ai/ai.controller.js.map +1 -1
  20. package/dist/ai/ai.module.d.ts.map +1 -1
  21. package/dist/ai/ai.module.js +3 -2
  22. package/dist/ai/ai.module.js.map +1 -1
  23. package/dist/ai/ai.service.d.ts +30 -1
  24. package/dist/ai/ai.service.d.ts.map +1 -1
  25. package/dist/ai/ai.service.js +97 -3
  26. package/dist/ai/ai.service.js.map +1 -1
  27. package/dist/ai/dto/richtext-edit-html.dto.d.ts +5 -0
  28. package/dist/ai/dto/richtext-edit-html.dto.d.ts.map +1 -0
  29. package/dist/ai/dto/richtext-edit-html.dto.js +27 -0
  30. package/dist/ai/dto/richtext-edit-html.dto.js.map +1 -0
  31. package/dist/ai/richtext-ai.prompts.d.ts +5 -0
  32. package/dist/ai/richtext-ai.prompts.d.ts.map +1 -0
  33. package/dist/ai/richtext-ai.prompts.js +57 -0
  34. package/dist/ai/richtext-ai.prompts.js.map +1 -0
  35. package/dist/ai/richtext-ai.service.d.ts +34 -0
  36. package/dist/ai/richtext-ai.service.d.ts.map +1 -0
  37. package/dist/ai/richtext-ai.service.js +95 -0
  38. package/dist/ai/richtext-ai.service.js.map +1 -0
  39. package/dist/ai-instruction/ai-instruction.controller.d.ts +5 -5
  40. package/dist/auth/auth.controller.d.ts +66 -7
  41. package/dist/auth/auth.controller.d.ts.map +1 -1
  42. package/dist/auth/auth.controller.js +67 -23
  43. package/dist/auth/auth.controller.js.map +1 -1
  44. package/dist/auth/auth.module.d.ts.map +1 -1
  45. package/dist/auth/auth.module.js +2 -0
  46. package/dist/auth/auth.module.js.map +1 -1
  47. package/dist/auth/auth.service.d.ts +136 -4
  48. package/dist/auth/auth.service.d.ts.map +1 -1
  49. package/dist/auth/auth.service.js +246 -48
  50. package/dist/auth/auth.service.js.map +1 -1
  51. package/dist/auth/dto/confirm-email.dto.d.ts +4 -0
  52. package/dist/auth/dto/confirm-email.dto.d.ts.map +1 -0
  53. package/dist/auth/dto/confirm-email.dto.js +22 -0
  54. package/dist/auth/dto/confirm-email.dto.js.map +1 -0
  55. package/dist/auth/dto/resend-confirmation.dto.d.ts +8 -0
  56. package/dist/auth/dto/resend-confirmation.dto.d.ts.map +1 -0
  57. package/dist/auth/dto/resend-confirmation.dto.js +36 -0
  58. package/dist/auth/dto/resend-confirmation.dto.js.map +1 -0
  59. package/dist/authorize/authorize.controller.d.ts +1 -1
  60. package/dist/authorize/authorize.controller.d.ts.map +1 -1
  61. package/dist/authorize/authorize.controller.js +4 -2
  62. package/dist/authorize/authorize.controller.js.map +1 -1
  63. package/dist/authorize/authorize.service.d.ts +7 -0
  64. package/dist/authorize/authorize.service.d.ts.map +1 -1
  65. package/dist/authorize/authorize.service.js +1 -1
  66. package/dist/authorize/authorize.service.js.map +1 -1
  67. package/dist/challenge/challenge.service.d.ts +18 -5
  68. package/dist/challenge/challenge.service.d.ts.map +1 -1
  69. package/dist/challenge/challenge.service.js +50 -3
  70. package/dist/challenge/challenge.service.js.map +1 -1
  71. package/dist/core.module.d.ts.map +1 -1
  72. package/dist/core.module.js +17 -0
  73. package/dist/core.module.js.map +1 -1
  74. package/dist/dashboard/dashboard/dashboard.controller.d.ts +6 -6
  75. package/dist/dashboard/dashboard/dashboard.service.d.ts +6 -6
  76. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +4 -4
  77. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +4 -4
  78. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +1 -1
  79. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +1 -1
  80. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +2 -2
  81. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +2 -2
  82. package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +2 -2
  83. package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +2 -2
  84. package/dist/file/file.controller.d.ts +8 -1
  85. package/dist/file/file.controller.d.ts.map +1 -1
  86. package/dist/file/file.controller.js +45 -7
  87. package/dist/file/file.controller.js.map +1 -1
  88. package/dist/file/file.service.d.ts +128 -1
  89. package/dist/file/file.service.d.ts.map +1 -1
  90. package/dist/file/file.service.js +319 -8
  91. package/dist/file/file.service.js.map +1 -1
  92. package/dist/file/image-optimization.service.d.ts +43 -0
  93. package/dist/file/image-optimization.service.d.ts.map +1 -1
  94. package/dist/file/image-optimization.service.js +154 -0
  95. package/dist/file/image-optimization.service.js.map +1 -1
  96. package/dist/file/provider/abstract.provider.d.ts +16 -0
  97. package/dist/file/provider/abstract.provider.d.ts.map +1 -1
  98. package/dist/file/provider/abstract.provider.js +4 -0
  99. package/dist/file/provider/abstract.provider.js.map +1 -1
  100. package/dist/file/provider/gcs.provider.d.ts +2 -0
  101. package/dist/file/provider/gcs.provider.d.ts.map +1 -1
  102. package/dist/file/provider/gcs.provider.js +10 -0
  103. package/dist/file/provider/gcs.provider.js.map +1 -1
  104. package/dist/file/provider/local.provider.d.ts +1 -0
  105. package/dist/file/provider/local.provider.d.ts.map +1 -1
  106. package/dist/file/provider/local.provider.js +13 -0
  107. package/dist/file/provider/local.provider.js.map +1 -1
  108. package/dist/file/provider/s3.provider.d.ts +5 -0
  109. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  110. package/dist/file/provider/s3.provider.js +15 -0
  111. package/dist/file/provider/s3.provider.js.map +1 -1
  112. package/dist/file/provider/spaces.provider.d.ts +5 -0
  113. package/dist/file/provider/spaces.provider.d.ts.map +1 -1
  114. package/dist/file/provider/spaces.provider.js +16 -0
  115. package/dist/file/provider/spaces.provider.js.map +1 -1
  116. package/dist/impersonation/dto/redeem-impersonation.dto.d.ts +4 -0
  117. package/dist/impersonation/dto/redeem-impersonation.dto.d.ts.map +1 -0
  118. package/dist/impersonation/dto/redeem-impersonation.dto.js +23 -0
  119. package/dist/impersonation/dto/redeem-impersonation.dto.js.map +1 -0
  120. package/dist/impersonation/dto/start-impersonation.dto.d.ts +7 -0
  121. package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -0
  122. package/dist/impersonation/dto/start-impersonation.dto.js +27 -0
  123. package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -0
  124. package/dist/impersonation/impersonation-restrictions.d.ts +26 -0
  125. package/dist/impersonation/impersonation-restrictions.d.ts.map +1 -0
  126. package/dist/impersonation/impersonation-restrictions.js +76 -0
  127. package/dist/impersonation/impersonation-restrictions.js.map +1 -0
  128. package/dist/impersonation/impersonation.controller.d.ts +90 -0
  129. package/dist/impersonation/impersonation.controller.d.ts.map +1 -0
  130. package/dist/impersonation/impersonation.controller.js +135 -0
  131. package/dist/impersonation/impersonation.controller.js.map +1 -0
  132. package/dist/impersonation/impersonation.module.d.ts +8 -0
  133. package/dist/impersonation/impersonation.module.d.ts.map +1 -0
  134. package/dist/impersonation/impersonation.module.js +44 -0
  135. package/dist/impersonation/impersonation.module.js.map +1 -0
  136. package/dist/impersonation/impersonation.service.d.ts +164 -0
  137. package/dist/impersonation/impersonation.service.d.ts.map +1 -0
  138. package/dist/impersonation/impersonation.service.js +408 -0
  139. package/dist/impersonation/impersonation.service.js.map +1 -0
  140. package/dist/index.d.ts +17 -0
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js +19 -0
  143. package/dist/index.js.map +1 -1
  144. package/dist/integration/services/outbox-polling.coordinator.d.ts +2 -0
  145. package/dist/integration/services/outbox-polling.coordinator.d.ts.map +1 -1
  146. package/dist/integration/services/outbox-polling.coordinator.js +50 -30
  147. package/dist/integration/services/outbox-polling.coordinator.js.map +1 -1
  148. package/dist/integration/services/outbox.service.d.ts.map +1 -1
  149. package/dist/integration/services/outbox.service.js +5 -1
  150. package/dist/integration/services/outbox.service.js.map +1 -1
  151. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  152. package/dist/integration-profile/integration-profile.secrets.js +3 -0
  153. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  154. package/dist/integration-profile/integration-profile.utils.d.ts +14 -0
  155. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  156. package/dist/integration-profile/integration-profile.utils.js +26 -0
  157. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  158. package/dist/integration-profile/testers/email.testers.d.ts.map +1 -1
  159. package/dist/integration-profile/testers/email.testers.js +28 -0
  160. package/dist/integration-profile/testers/email.testers.js.map +1 -1
  161. package/dist/language/en.json +11 -0
  162. package/dist/language/pt.json +11 -0
  163. package/dist/mail/dto/send.dto.d.ts +38 -1
  164. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  165. package/dist/mail/dto/send.dto.js +10 -0
  166. package/dist/mail/dto/send.dto.js.map +1 -1
  167. package/dist/mail/mail.controller.d.ts +1 -0
  168. package/dist/mail/mail.controller.d.ts.map +1 -1
  169. package/dist/mail/mail.module.d.ts.map +1 -1
  170. package/dist/mail/mail.module.js +2 -0
  171. package/dist/mail/mail.module.js.map +1 -1
  172. package/dist/mail/mail.service.d.ts +48 -4
  173. package/dist/mail/mail.service.d.ts.map +1 -1
  174. package/dist/mail/mail.service.js +187 -35
  175. package/dist/mail/mail.service.js.map +1 -1
  176. package/dist/mail-delivery/mail-delivery-provision.service.d.ts +21 -0
  177. package/dist/mail-delivery/mail-delivery-provision.service.d.ts.map +1 -0
  178. package/dist/mail-delivery/mail-delivery-provision.service.js +64 -0
  179. package/dist/mail-delivery/mail-delivery-provision.service.js.map +1 -0
  180. package/dist/mail-delivery/mail-delivery.constants.d.ts +17 -0
  181. package/dist/mail-delivery/mail-delivery.constants.d.ts.map +1 -0
  182. package/dist/mail-delivery/mail-delivery.constants.js +31 -0
  183. package/dist/mail-delivery/mail-delivery.constants.js.map +1 -0
  184. package/dist/mail-delivery/mail-delivery.controller.d.ts +19 -0
  185. package/dist/mail-delivery/mail-delivery.controller.d.ts.map +1 -0
  186. package/dist/mail-delivery/mail-delivery.controller.js +53 -0
  187. package/dist/mail-delivery/mail-delivery.controller.js.map +1 -0
  188. package/dist/mail-delivery/mail-delivery.module.d.ts +7 -0
  189. package/dist/mail-delivery/mail-delivery.module.d.ts.map +1 -0
  190. package/dist/mail-delivery/mail-delivery.module.js +36 -0
  191. package/dist/mail-delivery/mail-delivery.module.js.map +1 -0
  192. package/dist/mail-delivery/mail-delivery.service.d.ts +38 -0
  193. package/dist/mail-delivery/mail-delivery.service.d.ts.map +1 -0
  194. package/dist/mail-delivery/mail-delivery.service.js +140 -0
  195. package/dist/mail-delivery/mail-delivery.service.js.map +1 -0
  196. package/dist/mail-delivery/ses-event.parser.d.ts +27 -0
  197. package/dist/mail-delivery/ses-event.parser.d.ts.map +1 -0
  198. package/dist/mail-delivery/ses-event.parser.js +131 -0
  199. package/dist/mail-delivery/ses-event.parser.js.map +1 -0
  200. package/dist/mail-delivery/ses-webhook.service.d.ts +58 -0
  201. package/dist/mail-delivery/ses-webhook.service.d.ts.map +1 -0
  202. package/dist/mail-delivery/ses-webhook.service.js +214 -0
  203. package/dist/mail-delivery/ses-webhook.service.js.map +1 -0
  204. package/dist/mail-delivery/sns-message.util.d.ts +38 -0
  205. package/dist/mail-delivery/sns-message.util.d.ts.map +1 -0
  206. package/dist/mail-delivery/sns-message.util.js +109 -0
  207. package/dist/mail-delivery/sns-message.util.js.map +1 -0
  208. package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts +5 -0
  209. package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts.map +1 -1
  210. package/dist/mail-sent/dto/query-mail-sent-list.dto.js +6 -0
  211. package/dist/mail-sent/dto/query-mail-sent-list.dto.js.map +1 -1
  212. package/dist/mail-sent/mail-sent.controller.d.ts +39 -0
  213. package/dist/mail-sent/mail-sent.controller.d.ts.map +1 -1
  214. package/dist/mail-sent/mail-sent.service.d.ts +39 -0
  215. package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
  216. package/dist/mail-sent/mail-sent.service.js +45 -4
  217. package/dist/mail-sent/mail-sent.service.js.map +1 -1
  218. package/dist/mailbox/mailbox-fetcher.registry.d.ts +100 -0
  219. package/dist/mailbox/mailbox-fetcher.registry.d.ts.map +1 -0
  220. package/dist/mailbox/mailbox-fetcher.registry.js +59 -0
  221. package/dist/mailbox/mailbox-fetcher.registry.js.map +1 -0
  222. package/dist/mailbox/mailbox.module.d.ts +8 -0
  223. package/dist/mailbox/mailbox.module.d.ts.map +1 -0
  224. package/dist/mailbox/mailbox.module.js +27 -0
  225. package/dist/mailbox/mailbox.module.js.map +1 -0
  226. package/dist/meeting/meeting-provider.registry.d.ts +155 -0
  227. package/dist/meeting/meeting-provider.registry.d.ts.map +1 -0
  228. package/dist/meeting/meeting-provider.registry.js +53 -0
  229. package/dist/meeting/meeting-provider.registry.js.map +1 -0
  230. package/dist/meeting/meeting.constants.d.ts +47 -0
  231. package/dist/meeting/meeting.constants.d.ts.map +1 -0
  232. package/dist/meeting/meeting.constants.js +21 -0
  233. package/dist/meeting/meeting.constants.js.map +1 -0
  234. package/dist/meeting/meeting.module.d.ts +7 -0
  235. package/dist/meeting/meeting.module.d.ts.map +1 -0
  236. package/dist/meeting/meeting.module.js +26 -0
  237. package/dist/meeting/meeting.module.js.map +1 -0
  238. package/dist/middlewares/locale-injection.middleware.d.ts +12 -0
  239. package/dist/middlewares/locale-injection.middleware.d.ts.map +1 -1
  240. package/dist/middlewares/locale-injection.middleware.js +20 -4
  241. package/dist/middlewares/locale-injection.middleware.js.map +1 -1
  242. package/dist/oauth/providers/google.provider.d.ts +7 -0
  243. package/dist/oauth/providers/google.provider.d.ts.map +1 -1
  244. package/dist/oauth/providers/google.provider.js +43 -13
  245. package/dist/oauth/providers/google.provider.js.map +1 -1
  246. package/dist/observability/monitored-cron.d.ts +34 -0
  247. package/dist/observability/monitored-cron.d.ts.map +1 -0
  248. package/dist/observability/monitored-cron.js +118 -0
  249. package/dist/observability/monitored-cron.js.map +1 -0
  250. package/dist/pairing/dto/approve-reverse-pairing.dto.d.ts +12 -0
  251. package/dist/pairing/dto/approve-reverse-pairing.dto.d.ts.map +1 -0
  252. package/dist/pairing/dto/approve-reverse-pairing.dto.js +30 -0
  253. package/dist/pairing/dto/approve-reverse-pairing.dto.js.map +1 -0
  254. package/dist/pairing/dto/claim-pairing.dto.d.ts +11 -0
  255. package/dist/pairing/dto/claim-pairing.dto.d.ts.map +1 -0
  256. package/dist/pairing/dto/claim-pairing.dto.js +35 -0
  257. package/dist/pairing/dto/claim-pairing.dto.js.map +1 -0
  258. package/dist/pairing/dto/confirm-pairing.dto.d.ts +10 -0
  259. package/dist/pairing/dto/confirm-pairing.dto.d.ts.map +1 -0
  260. package/dist/pairing/dto/confirm-pairing.dto.js +24 -0
  261. package/dist/pairing/dto/confirm-pairing.dto.js.map +1 -0
  262. package/dist/pairing/dto/poll-reverse-pairing.dto.d.ts +5 -0
  263. package/dist/pairing/dto/poll-reverse-pairing.dto.d.ts.map +1 -0
  264. package/dist/pairing/dto/poll-reverse-pairing.dto.js +24 -0
  265. package/dist/pairing/dto/poll-reverse-pairing.dto.js.map +1 -0
  266. package/dist/pairing/dto/start-pairing.dto.d.ts +11 -0
  267. package/dist/pairing/dto/start-pairing.dto.d.ts.map +1 -0
  268. package/dist/pairing/dto/start-pairing.dto.js +30 -0
  269. package/dist/pairing/dto/start-pairing.dto.js.map +1 -0
  270. package/dist/pairing/dto/start-reverse-pairing.dto.d.ts +24 -0
  271. package/dist/pairing/dto/start-reverse-pairing.dto.d.ts.map +1 -0
  272. package/dist/pairing/dto/start-reverse-pairing.dto.js +47 -0
  273. package/dist/pairing/dto/start-reverse-pairing.dto.js.map +1 -0
  274. package/dist/pairing/pairing.controller.d.ts +118 -0
  275. package/dist/pairing/pairing.controller.d.ts.map +1 -0
  276. package/dist/pairing/pairing.controller.js +296 -0
  277. package/dist/pairing/pairing.controller.js.map +1 -0
  278. package/dist/pairing/pairing.module.d.ts +10 -0
  279. package/dist/pairing/pairing.module.d.ts.map +1 -0
  280. package/dist/pairing/pairing.module.js +40 -0
  281. package/dist/pairing/pairing.module.js.map +1 -0
  282. package/dist/pairing/pairing.service.d.ts +238 -0
  283. package/dist/pairing/pairing.service.d.ts.map +1 -0
  284. package/dist/pairing/pairing.service.js +495 -0
  285. package/dist/pairing/pairing.service.js.map +1 -0
  286. package/dist/pdf/pdf.service.d.ts +3 -6
  287. package/dist/pdf/pdf.service.d.ts.map +1 -1
  288. package/dist/pdf/pdf.service.js +8 -20
  289. package/dist/pdf/pdf.service.js.map +1 -1
  290. package/dist/profile/profile.controller.d.ts +11 -0
  291. package/dist/profile/profile.controller.d.ts.map +1 -1
  292. package/dist/profile/profile.service.d.ts +11 -0
  293. package/dist/profile/profile.service.d.ts.map +1 -1
  294. package/dist/profile/profile.service.js +20 -11
  295. package/dist/profile/profile.service.js.map +1 -1
  296. package/dist/redis/redis-pubsub.d.ts.map +1 -1
  297. package/dist/redis/redis-pubsub.js +44 -0
  298. package/dist/redis/redis-pubsub.js.map +1 -1
  299. package/dist/role/guards/role.guard.d.ts +5 -0
  300. package/dist/role/guards/role.guard.d.ts.map +1 -1
  301. package/dist/role/guards/role.guard.js +41 -39
  302. package/dist/role/guards/role.guard.js.map +1 -1
  303. package/dist/session/session.controller.d.ts +2 -0
  304. package/dist/session/session.controller.d.ts.map +1 -1
  305. package/dist/session/session.service.d.ts +39 -0
  306. package/dist/session/session.service.d.ts.map +1 -1
  307. package/dist/session/session.service.js +91 -8
  308. package/dist/session/session.service.js.map +1 -1
  309. package/dist/setting/brand-asset.service.d.ts +48 -0
  310. package/dist/setting/brand-asset.service.d.ts.map +1 -0
  311. package/dist/setting/brand-asset.service.js +130 -0
  312. package/dist/setting/brand-asset.service.js.map +1 -0
  313. package/dist/setting/setting.module.d.ts.map +1 -1
  314. package/dist/setting/setting.module.js +3 -2
  315. package/dist/setting/setting.module.js.map +1 -1
  316. package/dist/setting/setting.service.d.ts +33 -0
  317. package/dist/setting/setting.service.d.ts.map +1 -1
  318. package/dist/setting/setting.service.js +88 -0
  319. package/dist/setting/setting.service.js.map +1 -1
  320. package/dist/token/token.service.d.ts +23 -2
  321. package/dist/token/token.service.d.ts.map +1 -1
  322. package/dist/token/token.service.js +39 -4
  323. package/dist/token/token.service.js.map +1 -1
  324. package/dist/user/user.controller.d.ts +8 -22
  325. package/dist/user/user.controller.d.ts.map +1 -1
  326. package/dist/user/user.service.d.ts +44 -24
  327. package/dist/user/user.service.d.ts.map +1 -1
  328. package/dist/user/user.service.js +89 -6
  329. package/dist/user/user.service.js.map +1 -1
  330. package/dist/user-device/user-device.controller.d.ts +54 -0
  331. package/dist/user-device/user-device.controller.d.ts.map +1 -0
  332. package/dist/user-device/user-device.controller.js +103 -0
  333. package/dist/user-device/user-device.controller.js.map +1 -0
  334. package/dist/user-device/user-device.module.d.ts +3 -0
  335. package/dist/user-device/user-device.module.d.ts.map +1 -0
  336. package/dist/user-device/user-device.module.js +26 -0
  337. package/dist/user-device/user-device.module.js.map +1 -0
  338. package/dist/user-device/user-device.service.d.ts +71 -0
  339. package/dist/user-device/user-device.service.d.ts.map +1 -0
  340. package/dist/user-device/user-device.service.js +158 -0
  341. package/dist/user-device/user-device.service.js.map +1 -0
  342. package/dist/utils/device-key.d.ts +23 -0
  343. package/dist/utils/device-key.d.ts.map +1 -0
  344. package/dist/utils/device-key.js +31 -0
  345. package/dist/utils/device-key.js.map +1 -0
  346. package/dist/utils/geo-ip.d.ts +38 -0
  347. package/dist/utils/geo-ip.d.ts.map +1 -0
  348. package/dist/utils/geo-ip.js +122 -0
  349. package/dist/utils/geo-ip.js.map +1 -0
  350. package/dist/utils/locale-context.d.ts +10 -7
  351. package/dist/utils/locale-context.d.ts.map +1 -1
  352. package/dist/utils/locale-context.js +14 -8
  353. package/dist/utils/locale-context.js.map +1 -1
  354. package/dist/utils/security-event-vars.d.ts +56 -0
  355. package/dist/utils/security-event-vars.d.ts.map +1 -0
  356. package/dist/utils/security-event-vars.js +109 -0
  357. package/dist/utils/security-event-vars.js.map +1 -0
  358. package/dist/utils/user-agent.d.ts +19 -0
  359. package/dist/utils/user-agent.d.ts.map +1 -0
  360. package/dist/utils/user-agent.js +36 -0
  361. package/dist/utils/user-agent.js.map +1 -0
  362. package/dist/webhook-integration/webhook-integration.service.d.ts +5 -0
  363. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  364. package/dist/webhook-integration/webhook-integration.service.js +50 -4
  365. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  366. package/dist/webhook-integration/webhook-protocol.registry.d.ts +6 -0
  367. package/dist/webhook-integration/webhook-protocol.registry.d.ts.map +1 -1
  368. package/dist/webhook-integration/webhook-protocol.registry.js.map +1 -1
  369. package/hedhog/data/integration_provider.yaml +9 -0
  370. package/hedhog/data/mail.yaml +198 -62
  371. package/hedhog/data/mail_layout.yaml +43 -33
  372. package/hedhog/data/menu.yaml +2 -0
  373. package/hedhog/data/role.yaml +16 -0
  374. package/hedhog/data/route.yaml +172 -3
  375. package/hedhog/data/setting_group.yaml +178 -2
  376. package/hedhog/data/setting_subgroup.yaml +8 -0
  377. package/hedhog/frontend/app/_lib/hooks/use-core-access.test.tsx.ejs +125 -0
  378. package/hedhog/frontend/app/_lib/hooks/use-core-access.ts.ejs +29 -0
  379. package/hedhog/frontend/app/_lib/hooks/use-impersonation-access.test.ts.ejs +71 -0
  380. package/hedhog/frontend/app/_lib/hooks/use-impersonation-access.ts.ejs +32 -0
  381. package/hedhog/frontend/app/access-log/page.tsx.ejs +96 -22
  382. package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +17 -1
  383. package/hedhog/frontend/app/account/components/known-devices.tsx.ejs +89 -0
  384. package/hedhog/frontend/app/account/components/profile-form.tsx.ejs +2 -1
  385. package/hedhog/frontend/app/account/components/user-devices-list.tsx.ejs +186 -0
  386. package/hedhog/frontend/app/account/devices/page.tsx.ejs +5 -0
  387. package/hedhog/frontend/app/account/layout.tsx.ejs +2 -0
  388. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +298 -0
  389. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +376 -1236
  390. package/hedhog/frontend/app/mail/log/page.tsx.ejs +210 -3
  391. package/hedhog/frontend/app/mail/template/page.tsx.ejs +190 -132
  392. package/hedhog/frontend/app/users/active-session.tsx.ejs +58 -11
  393. package/hedhog/frontend/app/users/page.tsx.ejs +69 -10
  394. package/hedhog/frontend/app/users/simulate-access-dialog.test.tsx.ejs +202 -0
  395. package/hedhog/frontend/app/users/simulate-access-dialog.tsx.ejs +170 -0
  396. package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +19 -0
  397. package/hedhog/frontend/app/users/user-devices.tsx.ejs +89 -0
  398. package/hedhog/frontend/app/users/user-logs.tsx.ejs +13 -1
  399. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +46 -24
  400. package/hedhog/frontend/messages/en.json +146 -48
  401. package/hedhog/frontend/messages/pt.json +146 -48
  402. package/hedhog/table/access_log.yaml +7 -0
  403. package/hedhog/table/file.yaml +8 -0
  404. package/hedhog/table/mail_delivery_event.yaml +76 -0
  405. package/hedhog/table/mail_sent.yaml +23 -0
  406. package/hedhog/table/user_activity.yaml +9 -0
  407. package/hedhog/table/user_device.yaml +52 -0
  408. package/hedhog/table/user_session.yaml +20 -1
  409. package/package.json +6 -5
  410. package/src/access-log/access-log.controller.ts +1 -0
  411. package/src/access-log/access-log.interceptor.ts +5 -1
  412. package/src/access-log/access-log.service.spec.ts +33 -2
  413. package/src/access-log/access-log.service.ts +38 -0
  414. package/src/access-log/dto/query-access-log.dto.ts +5 -0
  415. package/src/ai/ai.controller.ts +9 -0
  416. package/src/ai/ai.module.ts +3 -2
  417. package/src/ai/ai.service.ts +150 -13
  418. package/src/ai/dto/richtext-edit-html.dto.ts +11 -0
  419. package/src/ai/richtext-ai.prompts.ts +57 -0
  420. package/src/ai/richtext-ai.service.ts +109 -0
  421. package/src/auth/auth.controller.ts +47 -8
  422. package/src/auth/auth.module.ts +2 -0
  423. package/src/auth/auth.service.spec.ts +383 -6
  424. package/src/auth/auth.service.ts +345 -56
  425. package/src/auth/dto/confirm-email.dto.ts +7 -0
  426. package/src/auth/dto/resend-confirmation.dto.ts +20 -0
  427. package/src/authorize/authorize.controller.ts +2 -0
  428. package/src/authorize/authorize.service.spec.ts +23 -0
  429. package/src/authorize/authorize.service.ts +8 -0
  430. package/src/challenge/challenge.service.spec.ts +73 -0
  431. package/src/challenge/challenge.service.ts +62 -3
  432. package/src/core.module.ts +19 -0
  433. package/src/file/file.controller.ts +54 -4
  434. package/src/file/file.service.spec.ts +275 -105
  435. package/src/file/file.service.ts +409 -14
  436. package/src/file/image-optimization.service.spec.ts +92 -0
  437. package/src/file/image-optimization.service.ts +202 -0
  438. package/src/file/provider/abstract.provider.ts +23 -0
  439. package/src/file/provider/gcs.provider.ts +17 -0
  440. package/src/file/provider/local.provider.ts +21 -0
  441. package/src/file/provider/s3.provider.ts +25 -0
  442. package/src/file/provider/spaces.provider.ts +26 -0
  443. package/src/impersonation/dto/redeem-impersonation.dto.ts +8 -0
  444. package/src/impersonation/dto/start-impersonation.dto.ts +13 -0
  445. package/src/impersonation/impersonation-restrictions.ts +84 -0
  446. package/src/impersonation/impersonation.controller.ts +109 -0
  447. package/src/impersonation/impersonation.module.ts +31 -0
  448. package/src/impersonation/impersonation.service.spec.ts +427 -0
  449. package/src/impersonation/impersonation.service.ts +577 -0
  450. package/src/index.ts +21 -0
  451. package/src/integration/services/outbox-polling.coordinator.spec.ts +90 -0
  452. package/src/integration/services/outbox-polling.coordinator.ts +62 -40
  453. package/src/integration/services/outbox.service.spec.ts +8 -0
  454. package/src/integration/services/outbox.service.ts +19 -13
  455. package/src/integration-profile/integration-profile.secrets.ts +3 -0
  456. package/src/integration-profile/integration-profile.utils.ts +38 -0
  457. package/src/integration-profile/testers/email.testers.ts +34 -1
  458. package/src/language/en.json +11 -0
  459. package/src/language/pt.json +11 -0
  460. package/src/mail/dto/send.dto.ts +46 -2
  461. package/src/mail/mail-template.spec.ts +79 -2
  462. package/src/mail/mail.module.ts +2 -0
  463. package/src/mail/mail.service.spec.ts +307 -6
  464. package/src/mail/mail.service.ts +227 -30
  465. package/src/mail-delivery/mail-delivery-provision.service.ts +66 -0
  466. package/src/mail-delivery/mail-delivery.constants.ts +31 -0
  467. package/src/mail-delivery/mail-delivery.controller.ts +38 -0
  468. package/src/mail-delivery/mail-delivery.module.ts +23 -0
  469. package/src/mail-delivery/mail-delivery.service.spec.ts +136 -0
  470. package/src/mail-delivery/mail-delivery.service.ts +152 -0
  471. package/src/mail-delivery/ses-event.parser.spec.ts +140 -0
  472. package/src/mail-delivery/ses-event.parser.ts +191 -0
  473. package/src/mail-delivery/ses-webhook.service.spec.ts +170 -0
  474. package/src/mail-delivery/ses-webhook.service.ts +240 -0
  475. package/src/mail-delivery/sns-message.util.spec.ts +163 -0
  476. package/src/mail-delivery/sns-message.util.ts +125 -0
  477. package/src/mail-sent/dto/query-mail-sent-list.dto.ts +15 -0
  478. package/src/mail-sent/mail-sent.service.ts +46 -2
  479. package/src/mailbox/mailbox-fetcher.registry.ts +132 -0
  480. package/src/mailbox/mailbox.module.ts +14 -0
  481. package/src/meeting/meeting-provider.registry.ts +193 -0
  482. package/src/meeting/meeting.constants.ts +53 -0
  483. package/src/meeting/meeting.module.ts +13 -0
  484. package/src/middlewares/locale-injection.middleware.ts +25 -6
  485. package/src/oauth/providers/google.provider.ts +49 -15
  486. package/src/observability/monitored-cron.spec.ts +102 -0
  487. package/src/observability/monitored-cron.ts +110 -0
  488. package/src/pairing/dto/approve-reverse-pairing.dto.ts +20 -0
  489. package/src/pairing/dto/claim-pairing.dto.ts +19 -0
  490. package/src/pairing/dto/confirm-pairing.dto.ts +14 -0
  491. package/src/pairing/dto/poll-reverse-pairing.dto.ts +9 -0
  492. package/src/pairing/dto/start-pairing.dto.ts +19 -0
  493. package/src/pairing/dto/start-reverse-pairing.dto.ts +45 -0
  494. package/src/pairing/pairing.controller.ts +246 -0
  495. package/src/pairing/pairing.module.ts +27 -0
  496. package/src/pairing/pairing.service.spec.ts +462 -0
  497. package/src/pairing/pairing.service.ts +614 -0
  498. package/src/pdf/pdf.service.ts +6 -24
  499. package/src/profile/profile.service.ts +26 -8
  500. package/src/redis/redis-pubsub.ts +11 -0
  501. package/src/role/guards/role.guard.spec.ts +75 -0
  502. package/src/role/guards/role.guard.ts +64 -46
  503. package/src/session/session.service.spec.ts +81 -0
  504. package/src/session/session.service.ts +93 -6
  505. package/src/setting/brand-asset.service.ts +137 -0
  506. package/src/setting/setting.module.ts +3 -2
  507. package/src/setting/setting.service.spec.ts +79 -1
  508. package/src/setting/setting.service.ts +109 -1
  509. package/src/token/token.service.spec.ts +62 -0
  510. package/src/token/token.service.ts +57 -3
  511. package/src/user/user.service.spec.ts +33 -2
  512. package/src/user/user.service.ts +108 -6
  513. package/src/user-device/user-device.controller.ts +77 -0
  514. package/src/user-device/user-device.module.ts +13 -0
  515. package/src/user-device/user-device.service.spec.ts +234 -0
  516. package/src/user-device/user-device.service.ts +168 -0
  517. package/src/utils/device-key.spec.ts +57 -0
  518. package/src/utils/device-key.ts +32 -0
  519. package/src/utils/geo-ip.spec.ts +134 -0
  520. package/src/utils/geo-ip.ts +93 -0
  521. package/src/utils/locale-context.spec.ts +27 -1
  522. package/src/utils/locale-context.ts +15 -12
  523. package/src/utils/security-event-vars.spec.ts +161 -0
  524. package/src/utils/security-event-vars.ts +153 -0
  525. package/src/utils/user-agent.spec.ts +37 -0
  526. package/src/utils/user-agent.ts +46 -0
  527. package/src/webhook-integration/webhook-integration.service.ts +57 -3
  528. package/src/webhook-integration/webhook-protocol.registry.ts +6 -0
@@ -33,6 +33,12 @@ import {
33
33
  DialogHeader,
34
34
  DialogTitle,
35
35
  } from '@/components/ui/dialog';
36
+ import {
37
+ DropdownMenu,
38
+ DropdownMenuContent,
39
+ DropdownMenuItem,
40
+ DropdownMenuTrigger,
41
+ } from '@/components/ui/dropdown-menu';
36
42
  import { Input } from '@/components/ui/input';
37
43
  import { Label } from '@/components/ui/label';
38
44
  import {
@@ -46,6 +52,7 @@ import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
46
52
  import {
47
53
  Sheet,
48
54
  SheetDescription,
55
+ SheetFooter,
49
56
  SheetHeader,
50
57
  SheetTitle,
51
58
  } from '@/components/ui/sheet';
@@ -63,6 +70,7 @@ import { formatDate } from '@/lib/format-date';
63
70
  import { useApp } from '@hed-hog/next-app-provider';
64
71
  import {
65
72
  AlertCircle,
73
+ ChevronDown,
66
74
  Database,
67
75
  Download,
68
76
  FileDown,
@@ -932,72 +940,97 @@ export default function EmailTemplatesPage() {
932
940
  />
933
941
 
934
942
  <Sheet open={isDialogOpen} onOpenChange={setIsDialogOpen}>
935
- <ResizableSheetContent sheetId="mail-template-editor" defaultWidth={1152}>
936
- <SheetHeader>
937
- <SheetTitle>
938
- {editMode ? t('editTemplate') : t('newTemplateTitle')}
939
- </SheetTitle>
940
- <SheetDescription>
941
- {editMode
942
- ? t('editTemplateDescription')
943
- : t('newTemplateDescription')}
944
- </SheetDescription>
943
+ <ResizableSheetContent
944
+ sheetId="mail-template-editor"
945
+ defaultWidth={1152}
946
+ minWidth={760}
947
+ maxWidth={1440}
948
+ className="flex h-full min-h-0 w-full flex-col gap-0 overflow-hidden p-0"
949
+ >
950
+ <SheetHeader className="shrink-0 border-b px-4 py-4 text-left sm:px-6">
951
+ {/* pr-8: o botão de fechar do Radix fica em absolute top-4 right-4 */}
952
+ <div className="flex items-start gap-3 pr-8">
953
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary">
954
+ <MailIcon className="h-5 w-5" />
955
+ </div>
956
+ <div className="min-w-0 space-y-1">
957
+ <SheetTitle>
958
+ {editMode ? t('editTemplate') : t('newTemplateTitle')}
959
+ </SheetTitle>
960
+ <SheetDescription>
961
+ {editMode
962
+ ? t('editTemplateDescription')
963
+ : t('newTemplateDescription')}
964
+ </SheetDescription>
965
+ </div>
966
+ </div>
945
967
  </SheetHeader>
946
- <form onSubmit={handleSubmit} className="space-y-6">
947
- <div className="grid grid-cols-3 gap-6">
948
- <div className="space-y-4 overflow-y-auto max-h-[calc(90vh-200px)] pr-4">
949
- <div className="space-y-2">
950
- <Label htmlFor="slug">{t('slugLabel')}</Label>
951
- <Input
952
- id="slug"
953
- value={formData.slug}
954
- onChange={(e) =>
955
- setFormData({ ...formData, slug: e.target.value })
956
- }
957
- placeholder={t('slugPlaceholder')}
958
- required
959
- />
960
- </div>
961
968
 
962
- <div className="space-y-2">
963
- <Label htmlFor="subject">{t('subjectLabel')}</Label>
964
- <Input
965
- id="subject"
966
- value={formData.subject}
967
- onChange={(e) =>
968
- setFormData({ ...formData, subject: e.target.value })
969
- }
970
- placeholder={t('subjectPlaceholder')}
971
- required
972
- />
973
- </div>
969
+ <form onSubmit={handleSubmit} className="flex min-h-0 flex-1 flex-col">
970
+ <div className="grid min-h-0 flex-1 grid-cols-1 overflow-y-auto lg:grid-cols-[minmax(260px,320px)_1fr] lg:overflow-hidden">
971
+ <div className="space-y-5 border-b px-4 py-4 sm:px-6 lg:min-h-0 lg:overflow-y-auto lg:border-b-0 lg:border-r">
972
+ <section className="space-y-3">
973
+ <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
974
+ {t('sectionIdentification')}
975
+ </h3>
976
+
977
+ <div className="space-y-1.5">
978
+ <Label htmlFor="slug">{t('slugLabel')}</Label>
979
+ <Input
980
+ id="slug"
981
+ value={formData.slug}
982
+ onChange={(e) =>
983
+ setFormData({ ...formData, slug: e.target.value })
984
+ }
985
+ placeholder={t('slugPlaceholder')}
986
+ className="font-mono text-sm"
987
+ required
988
+ />
989
+ </div>
974
990
 
975
- <div className="space-y-2">
976
- <Label htmlFor="variables">{t('variablesLabel')}</Label>
977
- <TagsInput
978
- id="variables"
979
- value={formData.variables}
980
- onChange={(val) =>
981
- setFormData({ ...formData, variables: val })
982
- }
983
- placeholder={t('variablesPlaceholder')}
984
- />
985
- <p className="text-xs text-muted-foreground">
986
- {t('variablesHelp')}
987
- </p>
988
- </div>
991
+ <div className="space-y-1.5">
992
+ <Label htmlFor="subject">{t('subjectLabel')}</Label>
993
+ <Input
994
+ id="subject"
995
+ value={formData.subject}
996
+ onChange={(e) =>
997
+ setFormData({ ...formData, subject: e.target.value })
998
+ }
999
+ placeholder={t('subjectPlaceholder')}
1000
+ required
1001
+ />
1002
+ </div>
1003
+ </section>
1004
+
1005
+ <section className="space-y-3">
1006
+ <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
1007
+ {t('variablesLabel')}
1008
+ </h3>
1009
+
1010
+ <div className="space-y-1.5">
1011
+ <TagsInput
1012
+ id="variables"
1013
+ value={formData.variables}
1014
+ onChange={(val) =>
1015
+ setFormData({ ...formData, variables: val })
1016
+ }
1017
+ placeholder={t('variablesPlaceholder')}
1018
+ />
1019
+ <p className="text-xs text-muted-foreground">
1020
+ {t('variablesHelp')}
1021
+ </p>
1022
+ </div>
989
1023
 
990
- {formData.variables.length > 0 && (
991
- <div className="space-y-2">
992
- <h4 className="text-sm font-semibold">
993
- {t('availableVariables')}
994
- </h4>
995
- <div className="space-y-2">
1024
+ {formData.variables.length > 0 && (
1025
+ <div className="space-y-2 rounded-lg border bg-muted/30 p-3">
1026
+ <p className="text-xs font-medium text-muted-foreground">
1027
+ {t('availableVariables')}
1028
+ </p>
996
1029
  {formData.variables.map((v, idx) => (
997
1030
  <div key={idx} className="flex items-center gap-2">
998
1031
  <Badge
999
1032
  variant="outline"
1000
- className="font-mono min-w-30"
1033
+ className="w-32 shrink-0 justify-center bg-background font-mono"
1001
1034
  >
1002
1035
  {'{{' + v + '}}'}
1003
1036
  </Badge>
@@ -1010,105 +1043,130 @@ export default function EmailTemplatesPage() {
1010
1043
  [v]: e.target.value,
1011
1044
  })
1012
1045
  }
1013
- className="flex-1"
1046
+ className="h-9 min-w-0 flex-1 bg-background"
1014
1047
  />
1015
1048
  </div>
1016
1049
  ))}
1017
1050
  </div>
1018
- </div>
1019
- )}
1051
+ )}
1052
+ </section>
1020
1053
  </div>
1021
1054
 
1022
- <div className="col-span-2 space-y-4">
1023
- <div className="absolute top-4 right-8 space-y-2">
1024
- <Label htmlFor="locale-select">{t('localeLabel')}</Label>
1025
- <Select
1026
- value={selectedLocaleCode}
1027
- onValueChange={handleLocaleChange}
1028
- >
1029
- <SelectTrigger id="locale-select" className="bg-background">
1030
- <SelectValue />
1031
- </SelectTrigger>
1032
- <SelectContent>
1033
- {locales.map((locale) => (
1034
- <SelectItem key={locale.code} value={locale.code}>
1035
- {locale.name}
1036
- </SelectItem>
1037
- ))}
1038
- </SelectContent>
1039
- </Select>
1055
+ <div className="flex min-h-0 flex-col gap-3 px-4 py-4 sm:px-6">
1056
+ <div className="flex flex-wrap items-end justify-between gap-3">
1057
+ <Label htmlFor="body">{t('bodyLabel')}</Label>
1058
+ <div className="flex items-center gap-2">
1059
+ <Label
1060
+ htmlFor="locale-select"
1061
+ className="text-xs font-normal text-muted-foreground"
1062
+ >
1063
+ {t('localeLabel')}
1064
+ </Label>
1065
+ <Select
1066
+ value={selectedLocaleCode}
1067
+ onValueChange={handleLocaleChange}
1068
+ >
1069
+ <SelectTrigger
1070
+ id="locale-select"
1071
+ className="h-9 w-45 bg-background"
1072
+ >
1073
+ <SelectValue />
1074
+ </SelectTrigger>
1075
+ <SelectContent>
1076
+ {locales.map((locale) => (
1077
+ <SelectItem key={locale.code} value={locale.code}>
1078
+ {locale.name}
1079
+ </SelectItem>
1080
+ ))}
1081
+ </SelectContent>
1082
+ </Select>
1083
+ </div>
1040
1084
  </div>
1041
1085
 
1042
- <div className="space-y-2">
1043
- <Label htmlFor="body">{t('bodyLabel')}</Label>
1044
- <HtmlContentEditor
1045
- key={selectedLocaleCode}
1046
- value={formData.body}
1047
- onChange={(value) =>
1048
- setFormData({ ...formData, body: value })
1049
- }
1050
- variables={editorVariables}
1051
- previewHtml={previewHtml}
1052
- previewLoading={previewLoading}
1053
- zoomStorageKey="mail-template-html-editor-zoom"
1054
- className="h-[calc(90vh-260px)]"
1055
- warnings={
1056
- bodyBypassesLayout ? (
1057
- <div className="flex items-start gap-2 rounded-lg border border-amber-400/30 bg-amber-50 p-2.5 text-xs text-amber-800 dark:bg-amber-950/30 dark:text-amber-300">
1058
- <AlertCircle className="mt-0.5 h-3.5 w-3.5 shrink-0" />
1059
- <span>
1060
- <span className="font-medium">
1061
- {t('fullDocumentWarningTitle')}
1062
- </span>
1063
- {' — '}
1064
- {t('fullDocumentWarningDesc')}
1086
+ <HtmlContentEditor
1087
+ key={selectedLocaleCode}
1088
+ value={formData.body}
1089
+ onChange={(value) => setFormData({ ...formData, body: value })}
1090
+ variables={editorVariables}
1091
+ previewHtml={previewHtml}
1092
+ previewLoading={previewLoading}
1093
+ zoomStorageKey="mail-template-html-editor-zoom"
1094
+ className="min-h-100 flex-1"
1095
+ warnings={
1096
+ bodyBypassesLayout ? (
1097
+ <div className="flex items-start gap-2 rounded-lg border border-amber-400/30 bg-amber-50 p-2.5 text-xs text-amber-800 dark:bg-amber-950/30 dark:text-amber-300">
1098
+ <AlertCircle className="mt-0.5 h-3.5 w-3.5 shrink-0" />
1099
+ <span>
1100
+ <span className="font-medium">
1101
+ {t('fullDocumentWarningTitle')}
1065
1102
  </span>
1066
- </div>
1067
- ) : null
1068
- }
1069
- />
1070
- </div>
1103
+ {' — '}
1104
+ {t('fullDocumentWarningDesc')}
1105
+ </span>
1106
+ </div>
1107
+ ) : null
1108
+ }
1109
+ />
1071
1110
  </div>
1072
1111
  </div>
1073
1112
 
1074
- <div className="flex justify-between items-center pt-4 border-t">
1075
- <div className="flex gap-2">
1113
+ <SheetFooter className="sticky bottom-0 shrink-0 flex-row flex-wrap items-center justify-between gap-3 border-t bg-background/95 px-4 py-3 backdrop-blur sm:justify-between sm:px-6">
1114
+ <div className="flex items-center gap-2">
1076
1115
  <Button
1077
1116
  type="button"
1078
1117
  variant="outline"
1079
1118
  size="sm"
1080
- onClick={() => {
1081
- if (selectedTemplate) {
1082
- downloadYAML(selectedTemplate);
1083
- }
1084
- }}
1119
+ onClick={handleSendTestEmail}
1120
+ disabled={!formData.subject.trim() || !formData.body.trim()}
1085
1121
  >
1086
- <Download className="mr-2 h-4 w-4" />
1087
- {t('downloadYAML')}
1122
+ <MailIcon className="mr-2 h-4 w-4" />
1123
+ {t('sendTestEmail')}
1088
1124
  </Button>
1125
+
1126
+ {/* Baixar YAML e Gerar Migration dependem de um template salvo. */}
1127
+ <DropdownMenu>
1128
+ <DropdownMenuTrigger asChild>
1129
+ <Button type="button" variant="outline" size="sm">
1130
+ {t('moreActions')}
1131
+ <ChevronDown className="ml-2 h-4 w-4" />
1132
+ </Button>
1133
+ </DropdownMenuTrigger>
1134
+ <DropdownMenuContent align="start">
1135
+ <DropdownMenuItem
1136
+ disabled={!selectedTemplate}
1137
+ onSelect={() => {
1138
+ if (selectedTemplate) {
1139
+ downloadYAML(selectedTemplate);
1140
+ }
1141
+ }}
1142
+ >
1143
+ <Download className="mr-2 h-4 w-4" />
1144
+ {t('downloadYAML')}
1145
+ </DropdownMenuItem>
1146
+ <DropdownMenuItem
1147
+ disabled={!selectedTemplate}
1148
+ onSelect={handleGenerateMigration}
1149
+ >
1150
+ <Database className="mr-2 h-4 w-4" />
1151
+ {t('generateMigration')}
1152
+ </DropdownMenuItem>
1153
+ </DropdownMenuContent>
1154
+ </DropdownMenu>
1155
+ </div>
1156
+
1157
+ <div className="flex items-center gap-2">
1089
1158
  <Button
1090
1159
  type="button"
1091
1160
  variant="outline"
1092
- size="sm"
1093
- onClick={handleGenerateMigration}
1161
+ onClick={() => setIsDialogOpen(false)}
1094
1162
  >
1095
- <Database className="mr-2 h-4 w-4" />
1096
- {t('generateMigration')}
1163
+ {t('cancel')}
1097
1164
  </Button>
1098
- <Button
1099
- type="button"
1100
- variant="outline"
1101
- size="sm"
1102
- onClick={handleSendTestEmail}
1103
- >
1104
- <MailIcon className="mr-2 h-4 w-4" />
1105
- {t('sendTestEmail')}
1165
+ <Button type="submit" className="min-w-32">
1166
+ {editMode ? t('saveChanges') : t('createTemplate')}
1106
1167
  </Button>
1107
1168
  </div>
1108
- <Button type="submit" className="min-w-40">
1109
- {editMode ? t('saveChanges') : t('createTemplate')}
1110
- </Button>
1111
- </div>
1169
+ </SheetFooter>
1112
1170
  </form>
1113
1171
  </ResizableSheetContent>
1114
1172
  </Sheet>
@@ -2,7 +2,7 @@ import { Button } from '@/components/ui/button';
2
2
  import { formatDateTime } from '@/lib/format-date';
3
3
  import { User, UserSession } from '@hed-hog/api-types';
4
4
  import { useApp } from '@hed-hog/next-app-provider';
5
- import { Monitor } from 'lucide-react';
5
+ import { Monitor, VenetianMask } from 'lucide-react';
6
6
  import { useTranslations } from 'next-intl';
7
7
  import { toast } from 'sonner';
8
8
 
@@ -23,6 +23,16 @@ function parseUserAgent(ua: string) {
23
23
  return { os, browser };
24
24
  }
25
25
 
26
+ /**
27
+ * Sessão aberta por um operador via simulação de acesso. Precisa ficar visível
28
+ * aqui: sem a marca, ela é indistinguível de um acesso genuíno do usuário.
29
+ */
30
+ const isSimulated = (session: UserSession) =>
31
+ Boolean(session?.impersonator_user_id);
32
+
33
+ const impersonatorName = (session: UserSession) =>
34
+ session?.impersonator?.name || `#${session?.impersonator_user_id}`;
35
+
26
36
  interface IProps {
27
37
  editingUser: User;
28
38
  refetch: () => void;
@@ -73,13 +83,28 @@ export function ActiveSessions({ editingUser, refetch }: IProps) {
73
83
  </div>
74
84
  <div className="space-y-2">
75
85
  {currentSession ? (
76
- <div className="rounded-lg border p-3">
86
+ <div
87
+ className={`rounded-lg border p-3 ${isSimulated(currentSession) ? 'border-amber-300 bg-amber-50/40' : ''}`}
88
+ >
77
89
  <div className="flex items-center gap-3">
78
- <div className="rounded-md bg-blue-50 p-2">
79
- <Monitor className="h-5 w-5 text-blue-600" />
90
+ <div
91
+ className={`rounded-md p-2 ${isSimulated(currentSession) ? 'bg-amber-100' : 'bg-blue-50'}`}
92
+ >
93
+ {isSimulated(currentSession) ? (
94
+ <VenetianMask className="h-5 w-5 text-amber-600" />
95
+ ) : (
96
+ <Monitor className="h-5 w-5 text-blue-600" />
97
+ )}
80
98
  </div>
81
99
  <div className="flex-1">
82
100
  <p className="text-sm font-medium">{t('currentSession')}</p>
101
+ {isSimulated(currentSession) && (
102
+ <p className="text-xs font-medium text-amber-700">
103
+ {t('simulatedBy', {
104
+ name: impersonatorName(currentSession),
105
+ })}
106
+ </p>
107
+ )}
83
108
  <p className="text-xs text-muted-foreground">
84
109
  {parseUserAgent(currentSession.user_agent).os} ·{' '}
85
110
  {parseUserAgent(currentSession.user_agent).browser} ·{' '}
@@ -99,9 +124,15 @@ export function ActiveSessions({ editingUser, refetch }: IProps) {
99
124
  )}
100
125
  </p>
101
126
  </div>
102
- <span className="rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700">
103
- {t('active')}
104
- </span>
127
+ {isSimulated(currentSession) ? (
128
+ <span className="rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-800">
129
+ {t('simulatedSession')}
130
+ </span>
131
+ ) : (
132
+ <span className="rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700">
133
+ {t('active')}
134
+ </span>
135
+ )}
105
136
  </div>
106
137
  </div>
107
138
  ) : (
@@ -116,13 +147,29 @@ export function ActiveSessions({ editingUser, refetch }: IProps) {
116
147
  ? otherSessions.map((session: UserSession) => {
117
148
  const { os, browser } = parseUserAgent(session.user_agent);
118
149
  return (
119
- <div key={session.id} className="rounded-lg border p-3">
150
+ <div
151
+ key={session.id}
152
+ className={`rounded-lg border p-3 ${isSimulated(session) ? 'border-amber-300 bg-amber-50/40' : ''}`}
153
+ >
120
154
  <div className="flex items-center gap-3">
121
- <div className="rounded-md bg-slate-50 p-2">
122
- <Monitor className="h-5 w-5 text-slate-600" />
155
+ <div
156
+ className={`rounded-md p-2 ${isSimulated(session) ? 'bg-amber-100' : 'bg-slate-50'}`}
157
+ >
158
+ {isSimulated(session) ? (
159
+ <VenetianMask className="h-5 w-5 text-amber-600" />
160
+ ) : (
161
+ <Monitor className="h-5 w-5 text-slate-600" />
162
+ )}
123
163
  </div>
124
164
  <div className="flex-1">
125
- <p className="text-sm font-medium">{t('otherSession')}</p>
165
+ <p className="text-sm font-medium">
166
+ {isSimulated(session) ? t('simulatedSession') : t('otherSession')}
167
+ </p>
168
+ {isSimulated(session) && (
169
+ <p className="text-xs font-medium text-amber-700">
170
+ {t('simulatedBy', { name: impersonatorName(session) })}
171
+ </p>
172
+ )}
126
173
  <p className="text-xs text-muted-foreground">
127
174
  {os} · {browser} · {t('lastActive')}{' '}
128
175
  {formatDateTime(
@@ -59,9 +59,12 @@ import {
59
59
  ShieldCheck,
60
60
  UserPlus,
61
61
  Users,
62
+ VenetianMask,
62
63
  } from 'lucide-react';
63
64
  import { useTranslations } from 'next-intl';
64
65
  import { useCallback, useEffect, useMemo, useState } from 'react';
66
+ import { useImpersonationAccess } from '../_lib/hooks/use-impersonation-access';
67
+ import { SimulateAccessDialog } from './simulate-access-dialog';
65
68
  import { UserSheet } from './user-sheet';
66
69
 
67
70
  const USER_VIEW_STORAGE_KEY = 'core-user-view-mode';
@@ -80,12 +83,15 @@ const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
80
83
 
81
84
  export default function UserPage() {
82
85
  const t = useTranslations('core.UserPage');
83
- const { request, currentLocaleCode, getSettingValue } = useApp();
86
+ const simulationT = useTranslations('core.AccessSimulation');
87
+ const { request, currentLocaleCode, getSettingValue, user: appUser } = useApp();
84
88
 
85
89
  const [searchQuery, setSearchQuery] = useState('');
86
90
  const [isSheetOpen, setIsSheetOpen] = useState(false);
87
91
  const [selectedUserId, setSelectedUserId] = useState<number | null>(null);
88
92
  const [viewMode, setViewMode] = useState<UserViewMode>('table');
93
+ const [simulateTarget, setSimulateTarget] = useState<User | null>(null);
94
+ const { canSimulateAccess } = useImpersonationAccess();
89
95
 
90
96
  const [page, setPage] = useState(1);
91
97
  const { data: generalSettings } = useQuery<{
@@ -253,6 +259,19 @@ export default function UserPage() {
253
259
  [currentLocaleCode, getSettingValue]
254
260
  );
255
261
 
262
+ /**
263
+ * Esconde o botão nos dois casos que o backend recusaria de qualquer forma e
264
+ * que dá para saber daqui: o próprio usuário e conta desativada. Alvo com
265
+ * papel `admin` NÃO é filtrado aqui — o payload da listagem não traz papéis —,
266
+ * então essa recusa fica com o `POST /impersonation/start`.
267
+ */
268
+ const canSimulate = useCallback(
269
+ (user: User) =>
270
+ Number(user.id) !== Number((appUser as { id?: number } | null)?.id) &&
271
+ !(user as { deactivated_at?: string | null }).deactivated_at,
272
+ [appUser]
273
+ );
274
+
256
275
  const pageUserIds = useMemo(
257
276
  () =>
258
277
  ((paginate as PaginatedResult<User>)?.data ?? []).map((u) => Number(u.id)),
@@ -368,7 +387,22 @@ export default function UserPage() {
368
387
  id: 'actions',
369
388
  header: '',
370
389
  cell: ({ row }) => (
371
- <div className="flex justify-end">
390
+ <div className="flex justify-end gap-1">
391
+ {canSimulateAccess && canSimulate(row.original) && (
392
+ <Tooltip>
393
+ <TooltipTrigger asChild>
394
+ <Button
395
+ variant="ghost"
396
+ size="icon"
397
+ className="h-8 w-8 text-amber-600 hover:text-amber-700"
398
+ onClick={() => setSimulateTarget(row.original)}
399
+ >
400
+ <VenetianMask className="h-4 w-4" />
401
+ </Button>
402
+ </TooltipTrigger>
403
+ <TooltipContent>{simulationT('action')}</TooltipContent>
404
+ </Tooltip>
405
+ )}
372
406
  <Tooltip>
373
407
  <TooltipTrigger asChild>
374
408
  <Button
@@ -386,7 +420,7 @@ export default function UserPage() {
386
420
  ),
387
421
  },
388
422
  ],
389
- [t, getLastLoginLabel, presenceMap]
423
+ [t, simulationT, getLastLoginLabel, presenceMap, canSimulateAccess, canSimulate]
390
424
  );
391
425
 
392
426
  const tableData = useMemo(
@@ -586,13 +620,30 @@ export default function UserPage() {
586
620
  </div>
587
621
  </div>
588
622
  <div className="flex flex-col items-end gap-2">
589
- <Button
590
- variant="outline"
591
- size="sm"
592
- onClick={() => handleOpenEdit(user)}
593
- >
594
- {t('buttonEditUser')}
595
- </Button>
623
+ <div className="flex items-center gap-1">
624
+ {canSimulateAccess && canSimulate(user) && (
625
+ <Tooltip>
626
+ <TooltipTrigger asChild>
627
+ <Button
628
+ variant="outline"
629
+ size="icon"
630
+ className="h-8 w-8 text-amber-600 hover:text-amber-700"
631
+ onClick={() => setSimulateTarget(user)}
632
+ >
633
+ <VenetianMask className="h-4 w-4" />
634
+ </Button>
635
+ </TooltipTrigger>
636
+ <TooltipContent>{simulationT('action')}</TooltipContent>
637
+ </Tooltip>
638
+ )}
639
+ <Button
640
+ variant="outline"
641
+ size="sm"
642
+ onClick={() => handleOpenEdit(user)}
643
+ >
644
+ {t('buttonEditUser')}
645
+ </Button>
646
+ </div>
596
647
  <div className="mt-1">
597
648
  {user.suspended_until ? (
598
649
  <Badge
@@ -745,6 +796,14 @@ export default function UserPage() {
745
796
  userId={selectedUserId}
746
797
  onSuccess={refetch}
747
798
  />
799
+
800
+ <SimulateAccessDialog
801
+ open={Boolean(simulateTarget)}
802
+ onOpenChange={(open) => {
803
+ if (!open) setSimulateTarget(null);
804
+ }}
805
+ user={simulateTarget}
806
+ />
748
807
  </div>
749
808
  </Page>
750
809
  );