@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
@@ -13,6 +13,21 @@ export class QueryMailSentListDTO extends PaginationDTO {
13
13
  @IsString()
14
14
  hasError?: string;
15
15
 
16
+ /**
17
+ * Desfecho reportado pelo provedor. `pending` e a ausencia de desfecho: ele
18
+ * aceitou a mensagem e nao disse mais nada.
19
+ */
20
+ @IsOptional()
21
+ @Transform(({ value }) => String(value ?? '').trim().toLowerCase())
22
+ @IsIn(['all', 'pending', 'delivered', 'bounced', 'complained', 'rejected'])
23
+ deliveryStatus?:
24
+ | 'all'
25
+ | 'pending'
26
+ | 'delivered'
27
+ | 'bounced'
28
+ | 'complained'
29
+ | 'rejected';
30
+
16
31
  @IsOptional()
17
32
  @Transform(({ value }) => String(value ?? '').trim())
18
33
  @IsString()
@@ -42,7 +42,18 @@ export class MailSentService {
42
42
  ) { }
43
43
 
44
44
  async list(paginationParams: QueryMailSentListDTO) {
45
- const fields = ['subject', 'from', 'to', 'cc', 'bcc', 'body'];
45
+ // `provider_message_id` entra na busca porque e o unico identificador que o
46
+ // evento do provedor traz: sem ele, ler um bounce no console da AWS e achar
47
+ // o envio correspondente aqui exigia adivinhacao.
48
+ const fields = [
49
+ 'subject',
50
+ 'from',
51
+ 'to',
52
+ 'cc',
53
+ 'bcc',
54
+ 'body',
55
+ 'provider_message_id',
56
+ ];
46
57
  const OR: any[] = this.prismaService.createInsensitiveSearch(
47
58
  fields,
48
59
  paginationParams,
@@ -99,6 +110,17 @@ export class MailSentService {
99
110
  });
100
111
  }
101
112
 
113
+ const deliveryStatus = paginationParams.deliveryStatus?.trim();
114
+ if (deliveryStatus && deliveryStatus !== 'all') {
115
+ // `pending` e a ausencia de desfecho: o provedor aceitou e nao disse mais
116
+ // nada. E o estado em que ficam os envios que ninguem sabe se chegaram.
117
+ AND.push(
118
+ deliveryStatus === 'pending'
119
+ ? { delivery_status: null }
120
+ : { delivery_status: deliveryStatus },
121
+ );
122
+ }
123
+
102
124
  const createdAt: { gte?: Date; lte?: Date } = {};
103
125
  const createdAtFrom = paginationParams.createdAtFrom?.trim();
104
126
  const createdAtTo = paginationParams.createdAtTo?.trim();
@@ -146,6 +168,22 @@ export class MailSentService {
146
168
  updated_at: true,
147
169
  },
148
170
  },
171
+ // O que o provedor disse depois de aceitar. `mail_sent_user` so cobre
172
+ // destinatario que e usuario da plataforma; um solicitante externo nao
173
+ // deixava rastro nenhum de entrega.
174
+ mail_delivery_event: {
175
+ select: {
176
+ id: true,
177
+ recipient_email: true,
178
+ event_type: true,
179
+ bounce_type: true,
180
+ bounce_subtype: true,
181
+ diagnostic_code: true,
182
+ reporting_mta: true,
183
+ occurred_at: true,
184
+ },
185
+ orderBy: { occurred_at: 'desc' },
186
+ },
149
187
  },
150
188
  },
151
189
  );
@@ -198,9 +236,15 @@ export class MailSentService {
198
236
  };
199
237
  }
200
238
 
201
- async get(locale:string, id: number) {
239
+ async get(locale: string, id: number) {
202
240
  const mailSent = await this.prismaService.mail_sent.findUnique({
203
241
  where: { id: id },
242
+ // Sem os relacionamentos, abrir um envio direto pelo id devolvia um
243
+ // registro sem nenhuma informacao de entrega - so a listagem trazia.
244
+ include: {
245
+ mail_sent_user: true,
246
+ mail_delivery_event: { orderBy: { occurred_at: 'desc' } },
247
+ },
204
248
  });
205
249
 
206
250
  if (!mailSent) {
@@ -0,0 +1,132 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+
3
+ /**
4
+ * Uma mensagem recebida, ainda crua.
5
+ *
6
+ * O fetcher devolve o MIME e nada mais. Interpretar (parsear cabeçalhos, cortar
7
+ * citação, decidir se é autoresposta) é do consumidor — assim os dois provedores
8
+ * compartilham exatamente o mesmo caminho de leitura, e o core não precisa
9
+ * conhecer mailparser nem as regras de atendimento.
10
+ */
11
+ export interface RawInboundMessage {
12
+ /**
13
+ * Identidade da mensagem no provedor (Message-Id, id do Graph).
14
+ * É a chave de idempotência de quem consome.
15
+ */
16
+ externalId: string;
17
+ /** Mensagem RFC 822 completa. */
18
+ source: Buffer;
19
+ receivedAt: Date;
20
+ }
21
+
22
+ export interface MailboxFetchTarget {
23
+ /** Perfil de integração com as credenciais. */
24
+ integrationProfileId: number;
25
+ /** Endereço monitorado. No Graph, é também o alvo do acesso app-only. */
26
+ address: string;
27
+ folder: string;
28
+ /**
29
+ * Cursor OPACO, como o fetcher o gravou da última vez.
30
+ *
31
+ * Cada provedor escolhe o formato — UID + UIDVALIDITY no IMAP, deltaLink no
32
+ * Graph. Manter isso opaco é o que permite um campo só no banco servir aos
33
+ * dois sem o consumidor entender nenhum dos dois.
34
+ */
35
+ cursor: string | null;
36
+ markAsRead: boolean;
37
+ /** Teto por ciclo, para uma caixa esquecida não virar um poll infinito. */
38
+ maxMessages: number;
39
+ }
40
+
41
+ export interface MailboxFetchResult {
42
+ messages: RawInboundMessage[];
43
+ /** Cursor a gravar DEPOIS que as mensagens forem persistidas. */
44
+ cursor: string | null;
45
+ /**
46
+ * O provedor invalidou o cursor anterior (UIDVALIDITY novo, delta expirado).
47
+ * Serve para o consumidor registrar o fato — a releitura em si já vem
48
+ * resolvida no resultado.
49
+ */
50
+ cursorReset: boolean;
51
+ }
52
+
53
+ /** Resultado de um teste de leitura, no mesmo formato do `MailVerifyResult`. */
54
+ export interface MailboxVerifyResult {
55
+ ok: boolean;
56
+ /** Evidência legível do sucesso. Nunca contém credencial. */
57
+ info?: string;
58
+ /** Motivo legível da falha. Nunca contém credencial. */
59
+ error?: string;
60
+ }
61
+
62
+ /**
63
+ * Lê uma caixa de correio.
64
+ *
65
+ * Implementações vivem nas libraries donas do protocolo (IMAP no `sac`,
66
+ * Microsoft Graph no `microsoft`) e se registram aqui no boot.
67
+ */
68
+ export interface IMailboxFetcher {
69
+ /** Falso quando o provedor está desligado ou mal configurado nesta instalação. */
70
+ isAvailable(): Promise<boolean>;
71
+ fetch(target: MailboxFetchTarget): Promise<MailboxFetchResult>;
72
+ /**
73
+ * Confere se ESTA caixa pode ser lida agora, exercitando o caminho real.
74
+ *
75
+ * Existe porque testar o perfil de integração não é a mesma coisa que testar a
76
+ * caixa: para o Entra, o teste do perfil só pede um token e passa mesmo sem
77
+ * permissão de e-mail, sem acesso àquele endereço e sem a pasta existir — ou
78
+ * seja, aprovaria uma caixa que nunca vai receber nada.
79
+ *
80
+ * Opcional: sem ela, o chamador cai no testador do perfil (o que basta para o
81
+ * IMAP, onde autenticar já prova o acesso).
82
+ */
83
+ verify?(target: MailboxFetchTarget): Promise<MailboxVerifyResult>;
84
+ }
85
+
86
+ /**
87
+ * Registro dos leitores de caixa, no mesmo padrão do MeetingProviderRegistry.
88
+ *
89
+ * Existe pelo mesmo motivo daquele: permitir que um módulo de negócio leia uma
90
+ * caixa do Microsoft 365 sem depender de `@hed-hog-pro/microsoft` — o que
91
+ * arrastaria as tabelas, as rotas e os crons daquela library para toda
92
+ * instalação, só para obter um token.
93
+ *
94
+ * A chave é o SLUG DO PROVIDER DE INTEGRAÇÃO (`imap`,
95
+ * `microsoft-entra-id-oauth`), então o caminho perfil → fetcher se resolve sem
96
+ * nenhuma tabela de-para.
97
+ */
98
+ @Injectable()
99
+ export class MailboxFetcherRegistry {
100
+ private readonly logger = new Logger(MailboxFetcherRegistry.name);
101
+ private readonly fetchers = new Map<string, IMailboxFetcher>();
102
+
103
+ register(providerSlug: string, implementation: IMailboxFetcher): void {
104
+ const key = normalizeProvider(providerSlug);
105
+ if (!key) throw new Error('Mailbox fetcher provider key is required.');
106
+
107
+ if (this.fetchers.has(key)) {
108
+ this.logger.warn(`Mailbox fetcher "${key}" was overwritten.`);
109
+ }
110
+
111
+ this.fetchers.set(key, implementation);
112
+ this.logger.log(`Registered mailbox fetcher "${key}"`);
113
+ }
114
+
115
+ get(providerSlug: string | null | undefined): IMailboxFetcher | null {
116
+ const key = normalizeProvider(providerSlug);
117
+ return key ? (this.fetchers.get(key) ?? null) : null;
118
+ }
119
+
120
+ has(providerSlug: string | null | undefined): boolean {
121
+ return this.get(providerSlug) !== null;
122
+ }
123
+
124
+ /** Providers que sabem ler caixa nesta instalação (a UI filtra por isto). */
125
+ list(): string[] {
126
+ return [...this.fetchers.keys()].sort();
127
+ }
128
+ }
129
+
130
+ function normalizeProvider(providerSlug: string | null | undefined): string {
131
+ return String(providerSlug ?? '').trim().toLowerCase();
132
+ }
@@ -0,0 +1,14 @@
1
+ import { Global, Module } from '@nestjs/common';
2
+ import { MailboxFetcherRegistry } from './mailbox-fetcher.registry';
3
+
4
+ /**
5
+ * Porta genérica de leitura de caixa de correio. Só carrega o registro — as
6
+ * implementações vêm de quem se registrar no boot (a library `sac` com a chave
7
+ * `imap`, a library `microsoft` com `microsoft-entra-id-oauth`).
8
+ */
9
+ @Global()
10
+ @Module({
11
+ providers: [MailboxFetcherRegistry],
12
+ exports: [MailboxFetcherRegistry],
13
+ })
14
+ export class MailboxModule {}
@@ -0,0 +1,193 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+
3
+ /**
4
+ * Pedido de criação de uma reunião online para uma entidade de negócio qualquer.
5
+ *
6
+ * A tripla `sourceModule`/`sourceEntity`/`sourceEntityId` é o que amarra a reunião
7
+ * à origem sem que o provedor precise conhecer o domínio: o LMS envia
8
+ * `('lms', 'course_class_session', '42')` e recebe de volta, no evento de gravação,
9
+ * exatamente a mesma tripla.
10
+ */
11
+ export interface CreateMeetingInput {
12
+ sourceModule: string;
13
+ sourceEntity: string;
14
+ sourceEntityId: string;
15
+ subject: string;
16
+ startAt: Date;
17
+ endAt: Date;
18
+ /** Liga a gravação automática, quando o provedor suportar. */
19
+ autoRecord?: boolean;
20
+ /** Usuário que pediu a criação (usado no modo delegado). */
21
+ requestedByUserId?: number;
22
+ /**
23
+ * Usuários que devem poder controlar a reunião (iniciar/parar gravação, admitir
24
+ * participantes). Sem isso, num organizador de serviço, o professor entra como
25
+ * participante comum.
26
+ */
27
+ coOrganizerUserIds?: number[];
28
+ /** Convidados do evento de calendário. */
29
+ attendeeEmails?: string[];
30
+ /** Local do evento (aula presencial/híbrida com reunião gerenciada). */
31
+ location?: string | null;
32
+ /** Texto da origem que acompanha o link no corpo do evento. */
33
+ description?: string | null;
34
+ }
35
+
36
+ export interface CreatedMeeting {
37
+ /** Link que o aluno abre. É o que vai para `meeting_url` da aula. */
38
+ joinUrl: string;
39
+ /** Id da reunião no provedor — necessário para buscar a gravação depois. */
40
+ providerMeetingId: string;
41
+ /** Id do evento de calendário, quando o provedor cria um. */
42
+ providerEventId?: string | null;
43
+ }
44
+
45
+ export interface MeetingSourceRef {
46
+ sourceModule: string;
47
+ sourceEntity: string;
48
+ sourceEntityIds: string[];
49
+ }
50
+
51
+ export type CreateMeetingResult =
52
+ | ({ ok: true } & CreatedMeeting)
53
+ | { ok: false; sourceEntityId: string; error: string };
54
+
55
+ /** Pedido de troca de convidados de uma reunião já existente. */
56
+ export interface UpdateMeetingAttendeesInput {
57
+ sourceModule: string;
58
+ sourceEntity: string;
59
+ sourceEntityId: string;
60
+ attendeeEmails: string[];
61
+ }
62
+
63
+ /**
64
+ * Pedido de atualização de assunto/horário/local de uma reunião já existente.
65
+ *
66
+ * Separado de `createMeeting` pelo mesmo motivo de `updateAttendees`: recriar
67
+ * geraria link novo e derrubaria quem já tem o evento antigo na agenda.
68
+ */
69
+ export interface UpdateMeetingDetailsInput {
70
+ sourceModule: string;
71
+ sourceEntity: string;
72
+ sourceEntityId: string;
73
+ subject: string;
74
+ startAt: Date;
75
+ endAt: Date;
76
+ location?: string | null;
77
+ description?: string | null;
78
+ }
79
+
80
+ /**
81
+ * Estado de uma reunião, na forma em que o módulo de origem precisa ver.
82
+ *
83
+ * Existe para que o dono da origem consulte o provedor em vez de ler a tabela
84
+ * dele: o LMS não deve saber que existe uma `microsoft_meeting`.
85
+ */
86
+ export interface MeetingSummary {
87
+ sourceEntityId: string;
88
+ joinUrl: string | null;
89
+ status: 'scheduled' | 'cancelled' | 'failed';
90
+ autoRecord: boolean;
91
+ /**
92
+ * Assunto e janela gravados no provedor, para a origem comparar com o que é
93
+ * desejado antes de mandar `updateDetails` — evita um PATCH a cada sync
94
+ * quando nada mudou. `null` em reuniões criadas antes deste campo existir.
95
+ */
96
+ subject: string | null;
97
+ startAt: Date | null;
98
+ endAt: Date | null;
99
+ location: string | null;
100
+ description: string | null;
101
+ /**
102
+ * Convidados atualmente no evento de calendário.
103
+ *
104
+ * Existe para o módulo de origem comparar antes de mandar atualizar: alterar
105
+ * a lista faz o provedor reenviar convite/atualização para todos, então um
106
+ * PATCH incondicional a cada sincronização viraria spam na caixa de quem
107
+ * acompanha a turma.
108
+ */
109
+ attendeeEmails: string[];
110
+ /** Estado da importação da gravação, quando `autoRecord` está ligado. */
111
+ recordingStatus:
112
+ | 'not_requested'
113
+ | 'pending'
114
+ | 'imported'
115
+ | 'unavailable'
116
+ | 'failed';
117
+ recordingFileId: number | null;
118
+ lastError: string | null;
119
+ }
120
+
121
+ /**
122
+ * Provedor de reuniões online (Teams hoje; Meet/Zoom cabem no mesmo contrato).
123
+ *
124
+ * Existe para que os módulos de negócio não dependam do pacote de um provedor
125
+ * específico: eles pedem ao registro e, se ninguém tiver se registrado, a
126
+ * funcionalidade simplesmente não aparece.
127
+ */
128
+ export interface IMeetingProvider {
129
+ /** Se a integração está configurada a ponto de aceitar chamadas. */
130
+ isAvailable(): Promise<boolean>;
131
+ createMeeting(input: CreateMeetingInput): Promise<CreatedMeeting>;
132
+ /** Criação em lote; nunca rejeita — devolve o erro por item. */
133
+ createMeetings(inputs: CreateMeetingInput[]): Promise<CreateMeetingResult[]>;
134
+ /** Cancela no provedor as reuniões das origens informadas. Tolerante a ausências. */
135
+ cancelBySource(ref: MeetingSourceRef): Promise<void>;
136
+ /**
137
+ * Troca a lista de convidados do evento de uma reunião já criada.
138
+ *
139
+ * Separado de `createMeeting` porque o custo é diferente: recriar a reunião
140
+ * geraria um link novo e derrubaria quem já tinha o antigo na agenda, enquanto
141
+ * ajustar convidados preserva a reunião. Tolerante a reunião inexistente.
142
+ */
143
+ updateAttendees(input: UpdateMeetingAttendeesInput): Promise<void>;
144
+ /**
145
+ * Atualiza assunto, horário e local do evento/reunião já criados, sem gerar
146
+ * link novo. Tolerante a reunião inexistente (mesmo padrão de updateAttendees).
147
+ */
148
+ updateDetails(input: UpdateMeetingDetailsInput): Promise<void>;
149
+ /** Estado das reuniões das origens informadas, para a UI do módulo de origem. */
150
+ findBySource(ref: MeetingSourceRef): Promise<MeetingSummary[]>;
151
+ }
152
+
153
+ /**
154
+ * Registro dos provedores de reunião, no mesmo padrão do WebhookProtocolRegistry:
155
+ * o módulo dono do provedor se registra no boot.
156
+ */
157
+ @Injectable()
158
+ export class MeetingProviderRegistry {
159
+ private readonly logger = new Logger(MeetingProviderRegistry.name);
160
+ private readonly providers = new Map<string, IMeetingProvider>();
161
+
162
+ register(provider: string, implementation: IMeetingProvider): void {
163
+ const key = normalizeProvider(provider);
164
+ if (!key) throw new Error('Meeting provider key is required.');
165
+
166
+ if (this.providers.has(key)) {
167
+ this.logger.warn(`Meeting provider "${key}" was overwritten.`);
168
+ }
169
+
170
+ this.providers.set(key, implementation);
171
+ this.logger.log(`Registered meeting provider "${key}"`);
172
+ }
173
+
174
+ get(provider: string | null | undefined): IMeetingProvider | null {
175
+ const key = normalizeProvider(provider);
176
+ return key ? (this.providers.get(key) ?? null) : null;
177
+ }
178
+
179
+ has(provider: string | null | undefined): boolean {
180
+ return this.get(provider) !== null;
181
+ }
182
+
183
+ /** Provedores registrados (para a UI listar o que existe). */
184
+ list(): string[] {
185
+ return [...this.providers.keys()].sort();
186
+ }
187
+ }
188
+
189
+ function normalizeProvider(provider: string | null | undefined): string {
190
+ return String(provider ?? '')
191
+ .trim()
192
+ .toLowerCase();
193
+ }
@@ -0,0 +1,53 @@
1
+ /** Chave do provedor Microsoft Teams no {@link MeetingProviderRegistry}. */
2
+ export const TEAMS_MEETING_PROVIDER = 'teams';
3
+
4
+ /**
5
+ * Evento de domínio publicado quando a gravação de uma reunião foi baixada e já
6
+ * existe como registro em `file`. Fica no core porque é o contrato entre quem
7
+ * publica (provedor da reunião) e quem consome (módulo dono da origem) — assim
8
+ * nenhum dos dois precisa importar o pacote do outro.
9
+ */
10
+ export const MEETING_RECORDING_AVAILABLE_EVENT =
11
+ 'microsoft.meeting.recording.available';
12
+
13
+ export interface MeetingRecordingAvailablePayload {
14
+ /** `file.id` do vídeo já enviado ao storage. */
15
+ fileId: number;
16
+ sourceModule: string;
17
+ sourceEntity: string;
18
+ sourceEntityId: string;
19
+ providerMeetingId?: string | null;
20
+ providerRecordingId?: string | null;
21
+ durationSeconds?: number | null;
22
+ joinUrl?: string | null;
23
+ }
24
+
25
+ /**
26
+ * Evento publicado quando o relatório de presença de uma reunião foi importado.
27
+ *
28
+ * Mesma razão de existir do evento de gravação: o provedor sabe quem entrou na
29
+ * reunião, mas não sabe o que é um aluno; o módulo de origem sabe quem está
30
+ * matriculado, mas não conhece o Graph. O encontro é aqui.
31
+ */
32
+ export const MEETING_ATTENDANCE_AVAILABLE_EVENT =
33
+ 'microsoft.meeting.attendance.available';
34
+
35
+ /** Um participante do relatório, na forma em que a origem precisa ver. */
36
+ export interface MeetingAttendanceRecord {
37
+ /**
38
+ * Nulo quando o provedor não identificou quem entrou (link aberto por
39
+ * convidado externo ou anônimo). A origem trata esse caso como "participante
40
+ * não identificado" em vez de descartar.
41
+ */
42
+ email: string | null;
43
+ displayName: string;
44
+ totalAttendanceSeconds: number;
45
+ }
46
+
47
+ export interface MeetingAttendanceAvailablePayload {
48
+ sourceModule: string;
49
+ sourceEntity: string;
50
+ sourceEntityId: string;
51
+ providerMeetingId?: string | null;
52
+ records: MeetingAttendanceRecord[];
53
+ }
@@ -0,0 +1,13 @@
1
+ import { Global, Module } from '@nestjs/common';
2
+ import { MeetingProviderRegistry } from './meeting-provider.registry';
3
+
4
+ /**
5
+ * Porta genérica de reuniões online. Só carrega o registro — a implementação vem
6
+ * de quem se registrar no boot (hoje a library `microsoft`, com a chave `teams`).
7
+ */
8
+ @Global()
9
+ @Module({
10
+ providers: [MeetingProviderRegistry],
11
+ exports: [MeetingProviderRegistry],
12
+ })
13
+ export class MeetingModule {}
@@ -1,15 +1,34 @@
1
+ import { localeStorage } from '@hed-hog/api-locale';
1
2
  import { Injectable, NestMiddleware } from '@nestjs/common';
2
3
  import { NextFunction, Request, Response } from 'express';
3
- import { localeStorage } from '../utils/locale-context';
4
4
 
5
+ /**
6
+ * Rede de seguranca do contexto de locale.
7
+ *
8
+ * Quem resolve o idioma e o `LocaleMiddleware` do `api-locale`, que ja abre o
9
+ * `AsyncLocalStorage` para o resto da cadeia. Este middleware so entra em acao
10
+ * quando aquele nao rodou (app que nao registrou o `LocaleModule`, ou uma
11
+ * ordem de middleware que o coloque depois), para que
12
+ * `getLocaleFromContext()` nunca leia um store vazio.
13
+ *
14
+ * Nao reinterpreta o header: sem a tabela `locale` a mao, validar aqui de novo
15
+ * era justamente como as duas camadas divergiam.
16
+ */
5
17
  @Injectable()
6
18
  export class LocaleInjectionMiddleware implements NestMiddleware {
7
19
  use(req: Request, res: Response, next: NextFunction) {
8
- const acceptLanguage = req.headers['accept-language'] || 'en';
9
- const locale = acceptLanguage.split(',')[0].split('-')[0];
20
+ if (localeStorage.getStore()) {
21
+ return next();
22
+ }
10
23
 
11
- localeStorage.run({ locale }, () => {
12
- next();
13
- });
24
+ localeStorage.run(
25
+ {
26
+ locale: req['locale'] || 'en',
27
+ detected: Boolean(req['localeDetected']),
28
+ },
29
+ () => {
30
+ next();
31
+ },
32
+ );
14
33
  }
15
34
  }
@@ -1,12 +1,23 @@
1
1
  import { PrismaService } from '@hed-hog/api-prisma';
2
2
  import { HttpService } from '@nestjs/axios';
3
- import { BadRequestException, forwardRef, Inject, Injectable } from '@nestjs/common';
3
+ import { BadRequestException, forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
4
4
  import { buildOAuthConfigFromIntegration } from '../../integration-profile/integration-profile.utils';
5
5
  import { SettingService } from '../../setting/setting.service';
6
6
  import { BaseOAuthProvider } from './abstract.provider';
7
7
 
8
8
  @Injectable()
9
9
  export class GoogleProvider extends BaseOAuthProvider {
10
+ private readonly logger = new Logger(GoogleProvider.name);
11
+
12
+ /**
13
+ * personFields da People API e o escopo sensível que cada um exige. Escopo sensível
14
+ * só entra na conta se estiver marcado em `oauth-google-scopes` e aprovado na
15
+ * verificação do Google; sem ele a People API responde 403.
16
+ */
17
+ private static readonly PEOPLE_FIELD_SCOPES: Record<string, string> = {
18
+ genders: 'https://www.googleapis.com/auth/user.gender.read',
19
+ birthdays: 'https://www.googleapis.com/auth/user.birthday.read',
20
+ };
10
21
 
11
22
  constructor(
12
23
  http: HttpService,
@@ -82,6 +93,7 @@ export class GoogleProvider extends BaseOAuthProvider {
82
93
 
83
94
  const peopleProfile = await this.getGoogleProfileFromAccessToken(
84
95
  token.access_token,
96
+ String(token.scope ?? ''),
85
97
  );
86
98
 
87
99
  return {
@@ -97,22 +109,44 @@ export class GoogleProvider extends BaseOAuthProvider {
97
109
  };
98
110
  }
99
111
 
100
- private async getGoogleProfileFromAccessToken(accessToken: string) {
101
- const url =
102
- 'https://people.googleapis.com/v1/people/me?personFields=genders,birthdays';
103
-
104
- const res = await fetch(url, {
105
- headers: {
106
- Authorization: `Bearer ${accessToken}`,
107
- },
108
- });
109
-
110
- if (!res.ok) {
111
- throw new Error(`Google People API error: ${res.statusText}`);
112
+ private async getGoogleProfileFromAccessToken(
113
+ accessToken: string,
114
+ grantedScopes: string,
115
+ ) {
116
+ const empty = { gender: null, birthday: null, raw: null };
117
+ const granted = new Set(grantedScopes.split(/\s+/).filter(Boolean));
118
+ const personFields = Object.entries(GoogleProvider.PEOPLE_FIELD_SCOPES)
119
+ .filter(([, scope]) => granted.has(scope))
120
+ .map(([field]) => field);
121
+
122
+ // Login com os escopos básicos (openid/email/profile) não passa pela People API:
123
+ // ela responderia 403 e derrubaria a autenticação inteira por um dado opcional.
124
+ if (!personFields.length) return empty;
125
+
126
+ const url = `https://people.googleapis.com/v1/people/me?personFields=${personFields.join(',')}`;
127
+
128
+ let data: any;
129
+ try {
130
+ const res = await fetch(url, {
131
+ headers: {
132
+ Authorization: `Bearer ${accessToken}`,
133
+ },
134
+ });
135
+
136
+ if (!res.ok) {
137
+ throw new Error(`Google People API error: ${res.statusText}`);
138
+ }
139
+
140
+ data = await res.json();
141
+ } catch (error) {
142
+ // People API desabilitada no projeto ou consentimento revogado não podem
143
+ // impedir o usuário de entrar.
144
+ this.logger.warn(
145
+ `Google People API indisponível, seguindo sem gênero/aniversário: ${(error as Error).message}`,
146
+ );
147
+ return empty;
112
148
  }
113
149
 
114
- const data: any = await res.json();
115
-
116
150
  const gender =
117
151
  data.genders?.find((g: any) => g.metadata?.primary)?.value ??
118
152
  data.genders?.[0]?.value ??