@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.
- package/README.md +39 -0
- package/dist/access-log/access-log.controller.d.ts.map +1 -1
- package/dist/access-log/access-log.controller.js +1 -1
- package/dist/access-log/access-log.controller.js.map +1 -1
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
- package/dist/access-log/access-log.interceptor.js +8 -5
- package/dist/access-log/access-log.interceptor.js.map +1 -1
- package/dist/access-log/access-log.service.d.ts +4 -0
- package/dist/access-log/access-log.service.d.ts.map +1 -1
- package/dist/access-log/access-log.service.js +31 -4
- package/dist/access-log/access-log.service.js.map +1 -1
- package/dist/access-log/dto/query-access-log.dto.d.ts +2 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -1
- package/dist/access-log/dto/query-access-log.dto.js +5 -0
- package/dist/access-log/dto/query-access-log.dto.js.map +1 -1
- package/dist/ai/ai.controller.d.ts +12 -8
- package/dist/ai/ai.controller.d.ts.map +1 -1
- package/dist/ai/ai.controller.js +17 -2
- package/dist/ai/ai.controller.js.map +1 -1
- package/dist/ai/ai.module.d.ts.map +1 -1
- package/dist/ai/ai.module.js +3 -2
- package/dist/ai/ai.module.js.map +1 -1
- package/dist/ai/ai.service.d.ts +30 -1
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +97 -3
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai/dto/richtext-edit-html.dto.d.ts +5 -0
- package/dist/ai/dto/richtext-edit-html.dto.d.ts.map +1 -0
- package/dist/ai/dto/richtext-edit-html.dto.js +27 -0
- package/dist/ai/dto/richtext-edit-html.dto.js.map +1 -0
- package/dist/ai/richtext-ai.prompts.d.ts +5 -0
- package/dist/ai/richtext-ai.prompts.d.ts.map +1 -0
- package/dist/ai/richtext-ai.prompts.js +57 -0
- package/dist/ai/richtext-ai.prompts.js.map +1 -0
- package/dist/ai/richtext-ai.service.d.ts +34 -0
- package/dist/ai/richtext-ai.service.d.ts.map +1 -0
- package/dist/ai/richtext-ai.service.js +95 -0
- package/dist/ai/richtext-ai.service.js.map +1 -0
- package/dist/ai-instruction/ai-instruction.controller.d.ts +5 -5
- package/dist/auth/auth.controller.d.ts +66 -7
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +67 -23
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +2 -0
- package/dist/auth/auth.module.js.map +1 -1
- package/dist/auth/auth.service.d.ts +136 -4
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +246 -48
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/dto/confirm-email.dto.d.ts +4 -0
- package/dist/auth/dto/confirm-email.dto.d.ts.map +1 -0
- package/dist/auth/dto/confirm-email.dto.js +22 -0
- package/dist/auth/dto/confirm-email.dto.js.map +1 -0
- package/dist/auth/dto/resend-confirmation.dto.d.ts +8 -0
- package/dist/auth/dto/resend-confirmation.dto.d.ts.map +1 -0
- package/dist/auth/dto/resend-confirmation.dto.js +36 -0
- package/dist/auth/dto/resend-confirmation.dto.js.map +1 -0
- package/dist/authorize/authorize.controller.d.ts +1 -1
- package/dist/authorize/authorize.controller.d.ts.map +1 -1
- package/dist/authorize/authorize.controller.js +4 -2
- package/dist/authorize/authorize.controller.js.map +1 -1
- package/dist/authorize/authorize.service.d.ts +7 -0
- package/dist/authorize/authorize.service.d.ts.map +1 -1
- package/dist/authorize/authorize.service.js +1 -1
- package/dist/authorize/authorize.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +18 -5
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +50 -3
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +17 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +6 -6
- package/dist/dashboard/dashboard/dashboard.service.d.ts +6 -6
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +4 -4
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +4 -4
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +2 -2
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +2 -2
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +2 -2
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +2 -2
- package/dist/file/file.controller.d.ts +8 -1
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +45 -7
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +128 -1
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +319 -8
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/image-optimization.service.d.ts +43 -0
- package/dist/file/image-optimization.service.d.ts.map +1 -1
- package/dist/file/image-optimization.service.js +154 -0
- package/dist/file/image-optimization.service.js.map +1 -1
- package/dist/file/provider/abstract.provider.d.ts +16 -0
- package/dist/file/provider/abstract.provider.d.ts.map +1 -1
- package/dist/file/provider/abstract.provider.js +4 -0
- package/dist/file/provider/abstract.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts +2 -0
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +10 -0
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts +1 -0
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +13 -0
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +5 -0
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +15 -0
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts +5 -0
- package/dist/file/provider/spaces.provider.d.ts.map +1 -1
- package/dist/file/provider/spaces.provider.js +16 -0
- package/dist/file/provider/spaces.provider.js.map +1 -1
- package/dist/impersonation/dto/redeem-impersonation.dto.d.ts +4 -0
- package/dist/impersonation/dto/redeem-impersonation.dto.d.ts.map +1 -0
- package/dist/impersonation/dto/redeem-impersonation.dto.js +23 -0
- package/dist/impersonation/dto/redeem-impersonation.dto.js.map +1 -0
- package/dist/impersonation/dto/start-impersonation.dto.d.ts +7 -0
- package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -0
- package/dist/impersonation/dto/start-impersonation.dto.js +27 -0
- package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -0
- package/dist/impersonation/impersonation-restrictions.d.ts +26 -0
- package/dist/impersonation/impersonation-restrictions.d.ts.map +1 -0
- package/dist/impersonation/impersonation-restrictions.js +76 -0
- package/dist/impersonation/impersonation-restrictions.js.map +1 -0
- package/dist/impersonation/impersonation.controller.d.ts +90 -0
- package/dist/impersonation/impersonation.controller.d.ts.map +1 -0
- package/dist/impersonation/impersonation.controller.js +135 -0
- package/dist/impersonation/impersonation.controller.js.map +1 -0
- package/dist/impersonation/impersonation.module.d.ts +8 -0
- package/dist/impersonation/impersonation.module.d.ts.map +1 -0
- package/dist/impersonation/impersonation.module.js +44 -0
- package/dist/impersonation/impersonation.module.js.map +1 -0
- package/dist/impersonation/impersonation.service.d.ts +164 -0
- package/dist/impersonation/impersonation.service.d.ts.map +1 -0
- package/dist/impersonation/impersonation.service.js +408 -0
- package/dist/impersonation/impersonation.service.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/integration/services/outbox-polling.coordinator.d.ts +2 -0
- package/dist/integration/services/outbox-polling.coordinator.d.ts.map +1 -1
- package/dist/integration/services/outbox-polling.coordinator.js +50 -30
- package/dist/integration/services/outbox-polling.coordinator.js.map +1 -1
- package/dist/integration/services/outbox.service.d.ts.map +1 -1
- package/dist/integration/services/outbox.service.js +5 -1
- package/dist/integration/services/outbox.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.js +3 -0
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.d.ts +14 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +26 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/integration-profile/testers/email.testers.d.ts.map +1 -1
- package/dist/integration-profile/testers/email.testers.js +28 -0
- package/dist/integration-profile/testers/email.testers.js.map +1 -1
- package/dist/language/en.json +11 -0
- package/dist/language/pt.json +11 -0
- package/dist/mail/dto/send.dto.d.ts +38 -1
- package/dist/mail/dto/send.dto.d.ts.map +1 -1
- package/dist/mail/dto/send.dto.js +10 -0
- package/dist/mail/dto/send.dto.js.map +1 -1
- package/dist/mail/mail.controller.d.ts +1 -0
- package/dist/mail/mail.controller.d.ts.map +1 -1
- package/dist/mail/mail.module.d.ts.map +1 -1
- package/dist/mail/mail.module.js +2 -0
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +48 -4
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +187 -35
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mail-delivery/mail-delivery-provision.service.d.ts +21 -0
- package/dist/mail-delivery/mail-delivery-provision.service.d.ts.map +1 -0
- package/dist/mail-delivery/mail-delivery-provision.service.js +64 -0
- package/dist/mail-delivery/mail-delivery-provision.service.js.map +1 -0
- package/dist/mail-delivery/mail-delivery.constants.d.ts +17 -0
- package/dist/mail-delivery/mail-delivery.constants.d.ts.map +1 -0
- package/dist/mail-delivery/mail-delivery.constants.js +31 -0
- package/dist/mail-delivery/mail-delivery.constants.js.map +1 -0
- package/dist/mail-delivery/mail-delivery.controller.d.ts +19 -0
- package/dist/mail-delivery/mail-delivery.controller.d.ts.map +1 -0
- package/dist/mail-delivery/mail-delivery.controller.js +53 -0
- package/dist/mail-delivery/mail-delivery.controller.js.map +1 -0
- package/dist/mail-delivery/mail-delivery.module.d.ts +7 -0
- package/dist/mail-delivery/mail-delivery.module.d.ts.map +1 -0
- package/dist/mail-delivery/mail-delivery.module.js +36 -0
- package/dist/mail-delivery/mail-delivery.module.js.map +1 -0
- package/dist/mail-delivery/mail-delivery.service.d.ts +38 -0
- package/dist/mail-delivery/mail-delivery.service.d.ts.map +1 -0
- package/dist/mail-delivery/mail-delivery.service.js +140 -0
- package/dist/mail-delivery/mail-delivery.service.js.map +1 -0
- package/dist/mail-delivery/ses-event.parser.d.ts +27 -0
- package/dist/mail-delivery/ses-event.parser.d.ts.map +1 -0
- package/dist/mail-delivery/ses-event.parser.js +131 -0
- package/dist/mail-delivery/ses-event.parser.js.map +1 -0
- package/dist/mail-delivery/ses-webhook.service.d.ts +58 -0
- package/dist/mail-delivery/ses-webhook.service.d.ts.map +1 -0
- package/dist/mail-delivery/ses-webhook.service.js +214 -0
- package/dist/mail-delivery/ses-webhook.service.js.map +1 -0
- package/dist/mail-delivery/sns-message.util.d.ts +38 -0
- package/dist/mail-delivery/sns-message.util.d.ts.map +1 -0
- package/dist/mail-delivery/sns-message.util.js +109 -0
- package/dist/mail-delivery/sns-message.util.js.map +1 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts +5 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts.map +1 -1
- package/dist/mail-sent/dto/query-mail-sent-list.dto.js +6 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.js.map +1 -1
- package/dist/mail-sent/mail-sent.controller.d.ts +39 -0
- package/dist/mail-sent/mail-sent.controller.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts +39 -0
- package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.service.js +45 -4
- package/dist/mail-sent/mail-sent.service.js.map +1 -1
- package/dist/mailbox/mailbox-fetcher.registry.d.ts +100 -0
- package/dist/mailbox/mailbox-fetcher.registry.d.ts.map +1 -0
- package/dist/mailbox/mailbox-fetcher.registry.js +59 -0
- package/dist/mailbox/mailbox-fetcher.registry.js.map +1 -0
- package/dist/mailbox/mailbox.module.d.ts +8 -0
- package/dist/mailbox/mailbox.module.d.ts.map +1 -0
- package/dist/mailbox/mailbox.module.js +27 -0
- package/dist/mailbox/mailbox.module.js.map +1 -0
- package/dist/meeting/meeting-provider.registry.d.ts +155 -0
- package/dist/meeting/meeting-provider.registry.d.ts.map +1 -0
- package/dist/meeting/meeting-provider.registry.js +53 -0
- package/dist/meeting/meeting-provider.registry.js.map +1 -0
- package/dist/meeting/meeting.constants.d.ts +47 -0
- package/dist/meeting/meeting.constants.d.ts.map +1 -0
- package/dist/meeting/meeting.constants.js +21 -0
- package/dist/meeting/meeting.constants.js.map +1 -0
- package/dist/meeting/meeting.module.d.ts +7 -0
- package/dist/meeting/meeting.module.d.ts.map +1 -0
- package/dist/meeting/meeting.module.js +26 -0
- package/dist/meeting/meeting.module.js.map +1 -0
- package/dist/middlewares/locale-injection.middleware.d.ts +12 -0
- package/dist/middlewares/locale-injection.middleware.d.ts.map +1 -1
- package/dist/middlewares/locale-injection.middleware.js +20 -4
- package/dist/middlewares/locale-injection.middleware.js.map +1 -1
- package/dist/oauth/providers/google.provider.d.ts +7 -0
- package/dist/oauth/providers/google.provider.d.ts.map +1 -1
- package/dist/oauth/providers/google.provider.js +43 -13
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/observability/monitored-cron.d.ts +34 -0
- package/dist/observability/monitored-cron.d.ts.map +1 -0
- package/dist/observability/monitored-cron.js +118 -0
- package/dist/observability/monitored-cron.js.map +1 -0
- package/dist/pairing/dto/approve-reverse-pairing.dto.d.ts +12 -0
- package/dist/pairing/dto/approve-reverse-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/approve-reverse-pairing.dto.js +30 -0
- package/dist/pairing/dto/approve-reverse-pairing.dto.js.map +1 -0
- package/dist/pairing/dto/claim-pairing.dto.d.ts +11 -0
- package/dist/pairing/dto/claim-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/claim-pairing.dto.js +35 -0
- package/dist/pairing/dto/claim-pairing.dto.js.map +1 -0
- package/dist/pairing/dto/confirm-pairing.dto.d.ts +10 -0
- package/dist/pairing/dto/confirm-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/confirm-pairing.dto.js +24 -0
- package/dist/pairing/dto/confirm-pairing.dto.js.map +1 -0
- package/dist/pairing/dto/poll-reverse-pairing.dto.d.ts +5 -0
- package/dist/pairing/dto/poll-reverse-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/poll-reverse-pairing.dto.js +24 -0
- package/dist/pairing/dto/poll-reverse-pairing.dto.js.map +1 -0
- package/dist/pairing/dto/start-pairing.dto.d.ts +11 -0
- package/dist/pairing/dto/start-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/start-pairing.dto.js +30 -0
- package/dist/pairing/dto/start-pairing.dto.js.map +1 -0
- package/dist/pairing/dto/start-reverse-pairing.dto.d.ts +24 -0
- package/dist/pairing/dto/start-reverse-pairing.dto.d.ts.map +1 -0
- package/dist/pairing/dto/start-reverse-pairing.dto.js +47 -0
- package/dist/pairing/dto/start-reverse-pairing.dto.js.map +1 -0
- package/dist/pairing/pairing.controller.d.ts +118 -0
- package/dist/pairing/pairing.controller.d.ts.map +1 -0
- package/dist/pairing/pairing.controller.js +296 -0
- package/dist/pairing/pairing.controller.js.map +1 -0
- package/dist/pairing/pairing.module.d.ts +10 -0
- package/dist/pairing/pairing.module.d.ts.map +1 -0
- package/dist/pairing/pairing.module.js +40 -0
- package/dist/pairing/pairing.module.js.map +1 -0
- package/dist/pairing/pairing.service.d.ts +238 -0
- package/dist/pairing/pairing.service.d.ts.map +1 -0
- package/dist/pairing/pairing.service.js +495 -0
- package/dist/pairing/pairing.service.js.map +1 -0
- package/dist/pdf/pdf.service.d.ts +3 -6
- package/dist/pdf/pdf.service.d.ts.map +1 -1
- package/dist/pdf/pdf.service.js +8 -20
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +11 -0
- package/dist/profile/profile.controller.d.ts.map +1 -1
- package/dist/profile/profile.service.d.ts +11 -0
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +20 -11
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/redis/redis-pubsub.d.ts.map +1 -1
- package/dist/redis/redis-pubsub.js +44 -0
- package/dist/redis/redis-pubsub.js.map +1 -1
- package/dist/role/guards/role.guard.d.ts +5 -0
- package/dist/role/guards/role.guard.d.ts.map +1 -1
- package/dist/role/guards/role.guard.js +41 -39
- package/dist/role/guards/role.guard.js.map +1 -1
- package/dist/session/session.controller.d.ts +2 -0
- package/dist/session/session.controller.d.ts.map +1 -1
- package/dist/session/session.service.d.ts +39 -0
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +91 -8
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/brand-asset.service.d.ts +48 -0
- package/dist/setting/brand-asset.service.d.ts.map +1 -0
- package/dist/setting/brand-asset.service.js +130 -0
- package/dist/setting/brand-asset.service.js.map +1 -0
- package/dist/setting/setting.module.d.ts.map +1 -1
- package/dist/setting/setting.module.js +3 -2
- package/dist/setting/setting.module.js.map +1 -1
- package/dist/setting/setting.service.d.ts +33 -0
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +88 -0
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/token/token.service.d.ts +23 -2
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +39 -4
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +8 -22
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.service.d.ts +44 -24
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +89 -6
- package/dist/user/user.service.js.map +1 -1
- package/dist/user-device/user-device.controller.d.ts +54 -0
- package/dist/user-device/user-device.controller.d.ts.map +1 -0
- package/dist/user-device/user-device.controller.js +103 -0
- package/dist/user-device/user-device.controller.js.map +1 -0
- package/dist/user-device/user-device.module.d.ts +3 -0
- package/dist/user-device/user-device.module.d.ts.map +1 -0
- package/dist/user-device/user-device.module.js +26 -0
- package/dist/user-device/user-device.module.js.map +1 -0
- package/dist/user-device/user-device.service.d.ts +71 -0
- package/dist/user-device/user-device.service.d.ts.map +1 -0
- package/dist/user-device/user-device.service.js +158 -0
- package/dist/user-device/user-device.service.js.map +1 -0
- package/dist/utils/device-key.d.ts +23 -0
- package/dist/utils/device-key.d.ts.map +1 -0
- package/dist/utils/device-key.js +31 -0
- package/dist/utils/device-key.js.map +1 -0
- package/dist/utils/geo-ip.d.ts +38 -0
- package/dist/utils/geo-ip.d.ts.map +1 -0
- package/dist/utils/geo-ip.js +122 -0
- package/dist/utils/geo-ip.js.map +1 -0
- package/dist/utils/locale-context.d.ts +10 -7
- package/dist/utils/locale-context.d.ts.map +1 -1
- package/dist/utils/locale-context.js +14 -8
- package/dist/utils/locale-context.js.map +1 -1
- package/dist/utils/security-event-vars.d.ts +56 -0
- package/dist/utils/security-event-vars.d.ts.map +1 -0
- package/dist/utils/security-event-vars.js +109 -0
- package/dist/utils/security-event-vars.js.map +1 -0
- package/dist/utils/user-agent.d.ts +19 -0
- package/dist/utils/user-agent.d.ts.map +1 -0
- package/dist/utils/user-agent.js +36 -0
- package/dist/utils/user-agent.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.service.d.ts +5 -0
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +50 -4
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/dist/webhook-integration/webhook-protocol.registry.d.ts +6 -0
- package/dist/webhook-integration/webhook-protocol.registry.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-protocol.registry.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +9 -0
- package/hedhog/data/mail.yaml +198 -62
- package/hedhog/data/mail_layout.yaml +43 -33
- package/hedhog/data/menu.yaml +2 -0
- package/hedhog/data/role.yaml +16 -0
- package/hedhog/data/route.yaml +172 -3
- package/hedhog/data/setting_group.yaml +178 -2
- package/hedhog/data/setting_subgroup.yaml +8 -0
- package/hedhog/frontend/app/_lib/hooks/use-core-access.test.tsx.ejs +125 -0
- package/hedhog/frontend/app/_lib/hooks/use-core-access.ts.ejs +29 -0
- package/hedhog/frontend/app/_lib/hooks/use-impersonation-access.test.ts.ejs +71 -0
- package/hedhog/frontend/app/_lib/hooks/use-impersonation-access.ts.ejs +32 -0
- package/hedhog/frontend/app/access-log/page.tsx.ejs +96 -22
- package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +17 -1
- package/hedhog/frontend/app/account/components/known-devices.tsx.ejs +89 -0
- package/hedhog/frontend/app/account/components/profile-form.tsx.ejs +2 -1
- package/hedhog/frontend/app/account/components/user-devices-list.tsx.ejs +186 -0
- package/hedhog/frontend/app/account/devices/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +2 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +298 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +376 -1236
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +210 -3
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +190 -132
- package/hedhog/frontend/app/users/active-session.tsx.ejs +58 -11
- package/hedhog/frontend/app/users/page.tsx.ejs +69 -10
- package/hedhog/frontend/app/users/simulate-access-dialog.test.tsx.ejs +202 -0
- package/hedhog/frontend/app/users/simulate-access-dialog.tsx.ejs +170 -0
- package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +19 -0
- package/hedhog/frontend/app/users/user-devices.tsx.ejs +89 -0
- package/hedhog/frontend/app/users/user-logs.tsx.ejs +13 -1
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +46 -24
- package/hedhog/frontend/messages/en.json +146 -48
- package/hedhog/frontend/messages/pt.json +146 -48
- package/hedhog/table/access_log.yaml +7 -0
- package/hedhog/table/file.yaml +8 -0
- package/hedhog/table/mail_delivery_event.yaml +76 -0
- package/hedhog/table/mail_sent.yaml +23 -0
- package/hedhog/table/user_activity.yaml +9 -0
- package/hedhog/table/user_device.yaml +52 -0
- package/hedhog/table/user_session.yaml +20 -1
- package/package.json +6 -5
- package/src/access-log/access-log.controller.ts +1 -0
- package/src/access-log/access-log.interceptor.ts +5 -1
- package/src/access-log/access-log.service.spec.ts +33 -2
- package/src/access-log/access-log.service.ts +38 -0
- package/src/access-log/dto/query-access-log.dto.ts +5 -0
- package/src/ai/ai.controller.ts +9 -0
- package/src/ai/ai.module.ts +3 -2
- package/src/ai/ai.service.ts +150 -13
- package/src/ai/dto/richtext-edit-html.dto.ts +11 -0
- package/src/ai/richtext-ai.prompts.ts +57 -0
- package/src/ai/richtext-ai.service.ts +109 -0
- package/src/auth/auth.controller.ts +47 -8
- package/src/auth/auth.module.ts +2 -0
- package/src/auth/auth.service.spec.ts +383 -6
- package/src/auth/auth.service.ts +345 -56
- package/src/auth/dto/confirm-email.dto.ts +7 -0
- package/src/auth/dto/resend-confirmation.dto.ts +20 -0
- package/src/authorize/authorize.controller.ts +2 -0
- package/src/authorize/authorize.service.spec.ts +23 -0
- package/src/authorize/authorize.service.ts +8 -0
- package/src/challenge/challenge.service.spec.ts +73 -0
- package/src/challenge/challenge.service.ts +62 -3
- package/src/core.module.ts +19 -0
- package/src/file/file.controller.ts +54 -4
- package/src/file/file.service.spec.ts +275 -105
- package/src/file/file.service.ts +409 -14
- package/src/file/image-optimization.service.spec.ts +92 -0
- package/src/file/image-optimization.service.ts +202 -0
- package/src/file/provider/abstract.provider.ts +23 -0
- package/src/file/provider/gcs.provider.ts +17 -0
- package/src/file/provider/local.provider.ts +21 -0
- package/src/file/provider/s3.provider.ts +25 -0
- package/src/file/provider/spaces.provider.ts +26 -0
- package/src/impersonation/dto/redeem-impersonation.dto.ts +8 -0
- package/src/impersonation/dto/start-impersonation.dto.ts +13 -0
- package/src/impersonation/impersonation-restrictions.ts +84 -0
- package/src/impersonation/impersonation.controller.ts +109 -0
- package/src/impersonation/impersonation.module.ts +31 -0
- package/src/impersonation/impersonation.service.spec.ts +427 -0
- package/src/impersonation/impersonation.service.ts +577 -0
- package/src/index.ts +21 -0
- package/src/integration/services/outbox-polling.coordinator.spec.ts +90 -0
- package/src/integration/services/outbox-polling.coordinator.ts +62 -40
- package/src/integration/services/outbox.service.spec.ts +8 -0
- package/src/integration/services/outbox.service.ts +19 -13
- package/src/integration-profile/integration-profile.secrets.ts +3 -0
- package/src/integration-profile/integration-profile.utils.ts +38 -0
- package/src/integration-profile/testers/email.testers.ts +34 -1
- package/src/language/en.json +11 -0
- package/src/language/pt.json +11 -0
- package/src/mail/dto/send.dto.ts +46 -2
- package/src/mail/mail-template.spec.ts +79 -2
- package/src/mail/mail.module.ts +2 -0
- package/src/mail/mail.service.spec.ts +307 -6
- package/src/mail/mail.service.ts +227 -30
- package/src/mail-delivery/mail-delivery-provision.service.ts +66 -0
- package/src/mail-delivery/mail-delivery.constants.ts +31 -0
- package/src/mail-delivery/mail-delivery.controller.ts +38 -0
- package/src/mail-delivery/mail-delivery.module.ts +23 -0
- package/src/mail-delivery/mail-delivery.service.spec.ts +136 -0
- package/src/mail-delivery/mail-delivery.service.ts +152 -0
- package/src/mail-delivery/ses-event.parser.spec.ts +140 -0
- package/src/mail-delivery/ses-event.parser.ts +191 -0
- package/src/mail-delivery/ses-webhook.service.spec.ts +170 -0
- package/src/mail-delivery/ses-webhook.service.ts +240 -0
- package/src/mail-delivery/sns-message.util.spec.ts +163 -0
- package/src/mail-delivery/sns-message.util.ts +125 -0
- package/src/mail-sent/dto/query-mail-sent-list.dto.ts +15 -0
- package/src/mail-sent/mail-sent.service.ts +46 -2
- package/src/mailbox/mailbox-fetcher.registry.ts +132 -0
- package/src/mailbox/mailbox.module.ts +14 -0
- package/src/meeting/meeting-provider.registry.ts +193 -0
- package/src/meeting/meeting.constants.ts +53 -0
- package/src/meeting/meeting.module.ts +13 -0
- package/src/middlewares/locale-injection.middleware.ts +25 -6
- package/src/oauth/providers/google.provider.ts +49 -15
- package/src/observability/monitored-cron.spec.ts +102 -0
- package/src/observability/monitored-cron.ts +110 -0
- package/src/pairing/dto/approve-reverse-pairing.dto.ts +20 -0
- package/src/pairing/dto/claim-pairing.dto.ts +19 -0
- package/src/pairing/dto/confirm-pairing.dto.ts +14 -0
- package/src/pairing/dto/poll-reverse-pairing.dto.ts +9 -0
- package/src/pairing/dto/start-pairing.dto.ts +19 -0
- package/src/pairing/dto/start-reverse-pairing.dto.ts +45 -0
- package/src/pairing/pairing.controller.ts +246 -0
- package/src/pairing/pairing.module.ts +27 -0
- package/src/pairing/pairing.service.spec.ts +462 -0
- package/src/pairing/pairing.service.ts +614 -0
- package/src/pdf/pdf.service.ts +6 -24
- package/src/profile/profile.service.ts +26 -8
- package/src/redis/redis-pubsub.ts +11 -0
- package/src/role/guards/role.guard.spec.ts +75 -0
- package/src/role/guards/role.guard.ts +64 -46
- package/src/session/session.service.spec.ts +81 -0
- package/src/session/session.service.ts +93 -6
- package/src/setting/brand-asset.service.ts +137 -0
- package/src/setting/setting.module.ts +3 -2
- package/src/setting/setting.service.spec.ts +79 -1
- package/src/setting/setting.service.ts +109 -1
- package/src/token/token.service.spec.ts +62 -0
- package/src/token/token.service.ts +57 -3
- package/src/user/user.service.spec.ts +33 -2
- package/src/user/user.service.ts +108 -6
- package/src/user-device/user-device.controller.ts +77 -0
- package/src/user-device/user-device.module.ts +13 -0
- package/src/user-device/user-device.service.spec.ts +234 -0
- package/src/user-device/user-device.service.ts +168 -0
- package/src/utils/device-key.spec.ts +57 -0
- package/src/utils/device-key.ts +32 -0
- package/src/utils/geo-ip.spec.ts +134 -0
- package/src/utils/geo-ip.ts +93 -0
- package/src/utils/locale-context.spec.ts +27 -1
- package/src/utils/locale-context.ts +15 -12
- package/src/utils/security-event-vars.spec.ts +161 -0
- package/src/utils/security-event-vars.ts +153 -0
- package/src/utils/user-agent.spec.ts +37 -0
- package/src/utils/user-agent.ts +46 -0
- package/src/webhook-integration/webhook-integration.service.ts +57 -3
- 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
|
-
|
|
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
|
-
|
|
9
|
-
|
|
20
|
+
if (localeStorage.getStore()) {
|
|
21
|
+
return next();
|
|
22
|
+
}
|
|
10
23
|
|
|
11
|
-
localeStorage.run(
|
|
12
|
-
|
|
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(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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 ??
|