@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
|
@@ -78,6 +78,7 @@ describe('AccessLogService', () => {
|
|
|
78
78
|
user_agent: 'UA',
|
|
79
79
|
method: 'GET',
|
|
80
80
|
path: '/api/x',
|
|
81
|
+
impersonator_user_id: null,
|
|
81
82
|
},
|
|
82
83
|
});
|
|
83
84
|
});
|
|
@@ -89,7 +90,32 @@ describe('AccessLogService', () => {
|
|
|
89
90
|
service.recordHttp({ method: 'POST', path: '/x' });
|
|
90
91
|
|
|
91
92
|
expect(prisma.access_log.create).toHaveBeenCalledWith({
|
|
92
|
-
data: {
|
|
93
|
+
data: {
|
|
94
|
+
user_id: null,
|
|
95
|
+
ip: null,
|
|
96
|
+
user_agent: null,
|
|
97
|
+
method: 'POST',
|
|
98
|
+
path: '/x',
|
|
99
|
+
impersonator_user_id: null,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('grava o operador quando o acesso e simulado', () => {
|
|
105
|
+
const { service, prisma } = makeService();
|
|
106
|
+
prisma.access_log.create.mockResolvedValue({});
|
|
107
|
+
|
|
108
|
+
// `userId` continua sendo o ALVO; o operador entra numa coluna propria,
|
|
109
|
+
// senao o log fica indistinguivel de um acesso genuino do usuario.
|
|
110
|
+
service.recordHttp({
|
|
111
|
+
userId: 3,
|
|
112
|
+
method: 'GET',
|
|
113
|
+
path: '/api/x',
|
|
114
|
+
impersonatorUserId: 42,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
expect(prisma.access_log.create).toHaveBeenCalledWith({
|
|
118
|
+
data: expect.objectContaining({ user_id: 3, impersonator_user_id: 42 }),
|
|
93
119
|
});
|
|
94
120
|
});
|
|
95
121
|
|
|
@@ -115,7 +141,12 @@ describe('AccessLogService', () => {
|
|
|
115
141
|
service.recordMcp({ userId: 9, mcpTool: 'search', mcpPrompt: 'q' });
|
|
116
142
|
|
|
117
143
|
expect(prisma.access_log.create).toHaveBeenCalledWith({
|
|
118
|
-
data: {
|
|
144
|
+
data: {
|
|
145
|
+
user_id: 9,
|
|
146
|
+
mcp_tool: 'search',
|
|
147
|
+
mcp_prompt: 'q',
|
|
148
|
+
impersonator_user_id: null,
|
|
149
|
+
},
|
|
119
150
|
});
|
|
120
151
|
});
|
|
121
152
|
});
|
|
@@ -10,12 +10,15 @@ interface RecordHttpData {
|
|
|
10
10
|
userAgent?: string;
|
|
11
11
|
method: string;
|
|
12
12
|
path: string;
|
|
13
|
+
/** Operador por tras de um acesso simulado; `userId` continua sendo o alvo. */
|
|
14
|
+
impersonatorUserId?: number;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
interface RecordMcpData {
|
|
16
18
|
userId?: number;
|
|
17
19
|
mcpTool: string;
|
|
18
20
|
mcpPrompt?: string;
|
|
21
|
+
impersonatorUserId?: number;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
type AccessLogListParams = {
|
|
@@ -30,6 +33,7 @@ type AccessLogListParams = {
|
|
|
30
33
|
createdAtFrom?: string;
|
|
31
34
|
createdAtTo?: string;
|
|
32
35
|
type?: 'http' | 'mcp' | 'all';
|
|
36
|
+
simulated?: 'all' | 'only' | 'exclude';
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
@Injectable()
|
|
@@ -52,6 +56,7 @@ export class AccessLogService {
|
|
|
52
56
|
user_agent: data.userAgent ?? null,
|
|
53
57
|
method: data.method,
|
|
54
58
|
path: data.path,
|
|
59
|
+
impersonator_user_id: data.impersonatorUserId ?? null,
|
|
55
60
|
},
|
|
56
61
|
})
|
|
57
62
|
.catch((e) => this.logger.warn(`Failed to persist HTTP access log: ${e.message}`));
|
|
@@ -64,6 +69,7 @@ export class AccessLogService {
|
|
|
64
69
|
user_id: data.userId ?? null,
|
|
65
70
|
mcp_tool: data.mcpTool,
|
|
66
71
|
mcp_prompt: data.mcpPrompt ?? null,
|
|
72
|
+
impersonator_user_id: data.impersonatorUserId ?? null,
|
|
67
73
|
},
|
|
68
74
|
})
|
|
69
75
|
.catch((e) => this.logger.warn(`Failed to persist MCP access log: ${e.message}`));
|
|
@@ -102,6 +108,12 @@ export class AccessLogService {
|
|
|
102
108
|
where.mcp_tool = { not: null };
|
|
103
109
|
}
|
|
104
110
|
|
|
111
|
+
if (params.simulated === 'only') {
|
|
112
|
+
where.impersonator_user_id = { not: null };
|
|
113
|
+
} else if (params.simulated === 'exclude') {
|
|
114
|
+
where.impersonator_user_id = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
105
117
|
const result = await this.pagination.paginate(this.prisma.access_log, {
|
|
106
118
|
...params,
|
|
107
119
|
fields: params.fields ?? '',
|
|
@@ -113,6 +125,24 @@ export class AccessLogService {
|
|
|
113
125
|
},
|
|
114
126
|
});
|
|
115
127
|
|
|
128
|
+
// `impersonator_user_id` e INT puro, sem FK (senao o db pull renomearia a
|
|
129
|
+
// relacao `user.access_log`), entao o nome do operador vem de uma consulta
|
|
130
|
+
// separada sobre os ids desta pagina.
|
|
131
|
+
const impersonatorIds = Array.from(
|
|
132
|
+
new Set(
|
|
133
|
+
(result.data as any[])
|
|
134
|
+
.map((log) => log.impersonator_user_id)
|
|
135
|
+
.filter((id): id is number => typeof id === 'number'),
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
const impersonators = impersonatorIds.length
|
|
139
|
+
? await this.prisma.user.findMany({
|
|
140
|
+
where: { id: { in: impersonatorIds } },
|
|
141
|
+
select: { id: true, name: true, photo_id: true },
|
|
142
|
+
})
|
|
143
|
+
: [];
|
|
144
|
+
const impersonatorById = new Map(impersonators.map((user) => [user.id, user]));
|
|
145
|
+
|
|
116
146
|
const data = (result.data as any[]).map((log) => {
|
|
117
147
|
const ua = log.user_agent ? new UAParser(log.user_agent).getResult() : null;
|
|
118
148
|
const geo = log.ip ? geoip.lookup(log.ip) : null;
|
|
@@ -124,6 +154,14 @@ export class AccessLogService {
|
|
|
124
154
|
os_version: ua?.os?.version ?? null,
|
|
125
155
|
country: geo?.country ?? null,
|
|
126
156
|
city: geo?.city ?? null,
|
|
157
|
+
impersonator:
|
|
158
|
+
typeof log.impersonator_user_id === 'number'
|
|
159
|
+
? (impersonatorById.get(log.impersonator_user_id) ?? {
|
|
160
|
+
id: log.impersonator_user_id,
|
|
161
|
+
name: '',
|
|
162
|
+
photo_id: null,
|
|
163
|
+
})
|
|
164
|
+
: null,
|
|
127
165
|
};
|
|
128
166
|
});
|
|
129
167
|
|
|
@@ -20,4 +20,9 @@ export class QueryAccessLogDto {
|
|
|
20
20
|
@IsOptional()
|
|
21
21
|
@IsIn(['http', 'mcp', 'all'])
|
|
22
22
|
type?: 'http' | 'mcp' | 'all';
|
|
23
|
+
|
|
24
|
+
/** Filtra acessos feitos durante uma simulacao de acesso. */
|
|
25
|
+
@IsOptional()
|
|
26
|
+
@IsIn(['all', 'only', 'exclude'])
|
|
27
|
+
simulated?: 'all' | 'only' | 'exclude';
|
|
23
28
|
}
|
package/src/ai/ai.controller.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { AiService } from './ai.service';
|
|
|
7
7
|
import { ChatAgentDTO } from './dto/chat-agent.dto';
|
|
8
8
|
import { ChatDTO } from './dto/chat.dto';
|
|
9
9
|
import { CreateAgentDTO } from './dto/create-agent.dto';
|
|
10
|
+
import { RichtextEditHtmlDTO } from './dto/richtext-edit-html.dto';
|
|
10
11
|
import { UpdateAgentDTO } from './dto/update-agent.dto';
|
|
12
|
+
import { RichtextAiService } from './richtext-ai.service';
|
|
11
13
|
|
|
12
14
|
@Role()
|
|
13
15
|
@Controller('ai')
|
|
@@ -15,6 +17,8 @@ export class AiController {
|
|
|
15
17
|
constructor(
|
|
16
18
|
@Inject(forwardRef(() => AiService))
|
|
17
19
|
private readonly aiService: AiService,
|
|
20
|
+
@Inject(forwardRef(() => RichtextAiService))
|
|
21
|
+
private readonly richtextAiService: RichtextAiService,
|
|
18
22
|
) {}
|
|
19
23
|
|
|
20
24
|
@Post('chat')
|
|
@@ -65,4 +69,9 @@ export class AiController {
|
|
|
65
69
|
) {
|
|
66
70
|
return this.aiService.chatWithAgent(slug, data, file);
|
|
67
71
|
}
|
|
72
|
+
|
|
73
|
+
@Post('richtext/edit-html')
|
|
74
|
+
async editRichtextHtml(@Body() data: RichtextEditHtmlDTO) {
|
|
75
|
+
return this.richtextAiService.editHtml(data);
|
|
76
|
+
}
|
|
68
77
|
}
|
package/src/ai/ai.module.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { FileModule } from '../file/file.module';
|
|
|
5
5
|
import { SettingModule } from '../setting/setting.module';
|
|
6
6
|
import { AiController } from './ai.controller';
|
|
7
7
|
import { AiService } from './ai.service';
|
|
8
|
+
import { RichtextAiService } from './richtext-ai.service';
|
|
8
9
|
|
|
9
10
|
@Module({
|
|
10
11
|
imports: [
|
|
@@ -14,7 +15,7 @@ import { AiService } from './ai.service';
|
|
|
14
15
|
forwardRef(() => AiInstructionModule),
|
|
15
16
|
],
|
|
16
17
|
controllers: [AiController],
|
|
17
|
-
providers: [AiService],
|
|
18
|
-
exports: [AiService],
|
|
18
|
+
providers: [AiService, RichtextAiService],
|
|
19
|
+
exports: [AiService, RichtextAiService],
|
|
19
20
|
})
|
|
20
21
|
export class AiModule {}
|
package/src/ai/ai.service.ts
CHANGED
|
@@ -40,7 +40,7 @@ import { ChatDTO } from './dto/chat.dto';
|
|
|
40
40
|
import { CreateAgentDTO } from './dto/create-agent.dto';
|
|
41
41
|
import { UpdateAgentDTO } from './dto/update-agent.dto';
|
|
42
42
|
|
|
43
|
-
type AiProvider = 'openai' | 'gemini' | 'deepseek';
|
|
43
|
+
type AiProvider = 'openai' | 'gemini' | 'deepseek' | 'claude';
|
|
44
44
|
|
|
45
45
|
/** Fallback call timeout when the active AI integration profile doesn't set `timeout_ms`. */
|
|
46
46
|
const DEFAULT_AI_CALL_TIMEOUT_MS = 120_000;
|
|
@@ -50,6 +50,20 @@ const AI_PROFILE_SETTING: Record<AiProvider, string> = {
|
|
|
50
50
|
openai: 'ai-openai-profile-id',
|
|
51
51
|
gemini: 'ai-gemini-profile-id',
|
|
52
52
|
deepseek: 'ai-deepseek-profile-id',
|
|
53
|
+
claude: 'ai-claude-profile-id',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Slug do provider de integração -> provider do chat.
|
|
58
|
+
*
|
|
59
|
+
* Usado quando o chamador escolhe um PERFIL (e não um provider): o provider sai
|
|
60
|
+
* do perfil, não do setting global.
|
|
61
|
+
*/
|
|
62
|
+
const PROVIDER_BY_INTEGRATION_SLUG: Record<string, AiProvider> = {
|
|
63
|
+
openai: 'openai',
|
|
64
|
+
gemini: 'gemini',
|
|
65
|
+
deepseek: 'deepseek',
|
|
66
|
+
claude: 'claude',
|
|
53
67
|
};
|
|
54
68
|
|
|
55
69
|
/**
|
|
@@ -82,6 +96,14 @@ type AiAttachment = {
|
|
|
82
96
|
buffer: Buffer;
|
|
83
97
|
};
|
|
84
98
|
|
|
99
|
+
type AiProfileCredentials = {
|
|
100
|
+
apiKey: string;
|
|
101
|
+
organization?: string;
|
|
102
|
+
model?: string;
|
|
103
|
+
timeoutMs?: number;
|
|
104
|
+
baseUrl?: string;
|
|
105
|
+
};
|
|
106
|
+
|
|
85
107
|
@Injectable()
|
|
86
108
|
export class AiService implements OnModuleInit {
|
|
87
109
|
private readonly logger = new Logger(AiService.name);
|
|
@@ -170,6 +192,14 @@ export class AiService implements OnModuleInit {
|
|
|
170
192
|
userPromptSlug: string;
|
|
171
193
|
variables?: TemplateVars;
|
|
172
194
|
provider?: AiProvider;
|
|
195
|
+
/**
|
|
196
|
+
* Perfil de integração a usar, no lugar do setting global por provider.
|
|
197
|
+
*
|
|
198
|
+
* Quando presente, o provider vem do perfil — é o que permite um módulo
|
|
199
|
+
* (o SAC, por exemplo) ter o próprio perfil de IA sem afetar o resto do
|
|
200
|
+
* sistema. Mesmo padrão que `sendTemplatedMail` já usa para e-mail.
|
|
201
|
+
*/
|
|
202
|
+
profileSlug?: string;
|
|
173
203
|
params?: AiChatModelParams;
|
|
174
204
|
contextSlug?: string;
|
|
175
205
|
}): Promise<{
|
|
@@ -194,8 +224,14 @@ export class AiService implements OnModuleInit {
|
|
|
194
224
|
// The system prompt represents the call, so its params win over the user one.
|
|
195
225
|
const stored = mergeModelParams(systemPrompt, userPrompt);
|
|
196
226
|
|
|
197
|
-
|
|
198
|
-
|
|
227
|
+
// Um perfil explícito manda no provider: pedir "openai" e apontar um perfil
|
|
228
|
+
// Claude bateria na API errada com a chave errada.
|
|
229
|
+
const target = await this.resolveProviderAndProfile(
|
|
230
|
+
input.provider,
|
|
231
|
+
input.profileSlug,
|
|
232
|
+
);
|
|
233
|
+
const provider = target.provider;
|
|
234
|
+
const aiProfile = target.profile;
|
|
199
235
|
const model =
|
|
200
236
|
stored.model || aiProfile.model || this.getDefaultModel(provider);
|
|
201
237
|
const timeoutMs = aiProfile.timeoutMs ?? DEFAULT_AI_CALL_TIMEOUT_MS;
|
|
@@ -582,6 +618,10 @@ export class AiService implements OnModuleInit {
|
|
|
582
618
|
return DEEPSEEK_DEFAULT_MODEL;
|
|
583
619
|
}
|
|
584
620
|
|
|
621
|
+
if (provider === 'claude') {
|
|
622
|
+
return 'claude-sonnet-4-5';
|
|
623
|
+
}
|
|
624
|
+
|
|
585
625
|
return 'gpt-4o-mini';
|
|
586
626
|
}
|
|
587
627
|
|
|
@@ -615,6 +655,10 @@ export class AiService implements OnModuleInit {
|
|
|
615
655
|
return this.chatWithGemini(input);
|
|
616
656
|
}
|
|
617
657
|
|
|
658
|
+
if (provider === 'claude') {
|
|
659
|
+
return this.chatWithClaude(input);
|
|
660
|
+
}
|
|
661
|
+
|
|
618
662
|
if (provider === 'deepseek') {
|
|
619
663
|
return this.chatWithOpenAi({
|
|
620
664
|
...input,
|
|
@@ -631,16 +675,42 @@ export class AiService implements OnModuleInit {
|
|
|
631
675
|
return (await this.getAiProfile(provider)).apiKey;
|
|
632
676
|
}
|
|
633
677
|
|
|
678
|
+
/**
|
|
679
|
+
* Resolve provider e credenciais juntos.
|
|
680
|
+
*
|
|
681
|
+
* Com `profileSlug`, o provider vem do perfil — o chamador escolheu uma conta
|
|
682
|
+
* concreta, e o setting global do provider não tem nada a dizer sobre ela.
|
|
683
|
+
*/
|
|
684
|
+
private async resolveProviderAndProfile(
|
|
685
|
+
provider?: AiProvider,
|
|
686
|
+
profileSlug?: string,
|
|
687
|
+
): Promise<{ provider: AiProvider; profile: AiProfileCredentials }> {
|
|
688
|
+
const slug = String(profileSlug ?? '').trim();
|
|
689
|
+
|
|
690
|
+
if (!slug) {
|
|
691
|
+
const resolvedProvider = provider || (await this.getDefaultProvider());
|
|
692
|
+
return {
|
|
693
|
+
provider: resolvedProvider,
|
|
694
|
+
profile: await this.getAiProfile(resolvedProvider),
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const profile = await this.loadAiProfileBySlug(slug);
|
|
699
|
+
const providerSlug = profile.providerSlug;
|
|
700
|
+
const mapped = PROVIDER_BY_INTEGRATION_SLUG[providerSlug];
|
|
701
|
+
|
|
702
|
+
if (!mapped) {
|
|
703
|
+
throw new BadRequestException(
|
|
704
|
+
`AI profile "${slug}" uses provider "${providerSlug}", which is not supported for chat. ` +
|
|
705
|
+
`Use one of: ${Object.keys(PROVIDER_BY_INTEGRATION_SLUG).join(', ')}.`,
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return { provider: mapped, profile: profile.config };
|
|
710
|
+
}
|
|
711
|
+
|
|
634
712
|
/** Resolves the active AI integration profile's credentials plus its optional model/timeout overrides. */
|
|
635
|
-
private async getAiProfile(
|
|
636
|
-
provider: AiProvider,
|
|
637
|
-
): Promise<{
|
|
638
|
-
apiKey: string;
|
|
639
|
-
organization?: string;
|
|
640
|
-
model?: string;
|
|
641
|
-
timeoutMs?: number;
|
|
642
|
-
baseUrl?: string;
|
|
643
|
-
}> {
|
|
713
|
+
private async getAiProfile(provider: AiProvider): Promise<AiProfileCredentials> {
|
|
644
714
|
const slug = AI_PROFILE_SETTING[provider] ?? AI_PROFILE_SETTING.openai;
|
|
645
715
|
const settings = await this.settingService.getSettingValues([slug]);
|
|
646
716
|
const profileSlug = String(settings[slug] ?? '').trim();
|
|
@@ -651,6 +721,13 @@ export class AiService implements OnModuleInit {
|
|
|
651
721
|
);
|
|
652
722
|
}
|
|
653
723
|
|
|
724
|
+
return (await this.loadAiProfileBySlug(profileSlug)).config;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
private async loadAiProfileBySlug(profileSlug: string): Promise<{
|
|
728
|
+
providerSlug: string;
|
|
729
|
+
config: AiProfileCredentials;
|
|
730
|
+
}> {
|
|
654
731
|
const profile = await this.prismaService.integration_profile.findUnique({
|
|
655
732
|
where: { slug: profileSlug },
|
|
656
733
|
include: { integration_provider: { select: { slug: true } } },
|
|
@@ -669,7 +746,7 @@ export class AiService implements OnModuleInit {
|
|
|
669
746
|
throw new BadRequestException(`AI profile "${profileSlug}" has no API key configured.`);
|
|
670
747
|
}
|
|
671
748
|
|
|
672
|
-
return aiConfig;
|
|
749
|
+
return { providerSlug: profile.integration_provider.slug, config: aiConfig };
|
|
673
750
|
}
|
|
674
751
|
|
|
675
752
|
/** Rejects with a timeout error if `promise` doesn't settle within `ms`. */
|
|
@@ -750,6 +827,66 @@ export class AiService implements OnModuleInit {
|
|
|
750
827
|
};
|
|
751
828
|
}
|
|
752
829
|
|
|
830
|
+
/**
|
|
831
|
+
* Anthropic (Claude).
|
|
832
|
+
*
|
|
833
|
+
* A API é diferente da da OpenAI em três pontos que quebram se reusarmos
|
|
834
|
+
* aquele caminho: autentica por `x-api-key` (não Bearer), exige o header de
|
|
835
|
+
* versão, e o system prompt é um campo à parte em vez de uma mensagem com
|
|
836
|
+
* `role: system`. `max_tokens` é obrigatório — sem ele a requisição é
|
|
837
|
+
* recusada, daí o padrão.
|
|
838
|
+
*
|
|
839
|
+
* Anexo não é suportado aqui: a Anthropic recebe imagem como bloco base64, e
|
|
840
|
+
* nenhum chamador do SAC manda anexo para o modelo.
|
|
841
|
+
*/
|
|
842
|
+
private async chatWithClaude({
|
|
843
|
+
message,
|
|
844
|
+
model,
|
|
845
|
+
systemPrompt,
|
|
846
|
+
apiKey,
|
|
847
|
+
params,
|
|
848
|
+
}: {
|
|
849
|
+
message: string;
|
|
850
|
+
model: string;
|
|
851
|
+
systemPrompt?: string;
|
|
852
|
+
apiKey?: string;
|
|
853
|
+
params?: AiChatModelParams;
|
|
854
|
+
}): Promise<{ content: string; usage?: { input: number; output: number; total: number } }> {
|
|
855
|
+
const key = apiKey ?? (await this.getAiApiKey('claude'));
|
|
856
|
+
|
|
857
|
+
const body: Record<string, unknown> = {
|
|
858
|
+
model,
|
|
859
|
+
max_tokens: params?.maxTokens ?? 4096,
|
|
860
|
+
messages: [{ role: 'user', content: message }],
|
|
861
|
+
};
|
|
862
|
+
if (systemPrompt) body.system = systemPrompt;
|
|
863
|
+
if (params?.temperature !== undefined && params?.temperature !== null) {
|
|
864
|
+
body.temperature = params.temperature;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const response = await axios.post('https://api.anthropic.com/v1/messages', body, {
|
|
868
|
+
headers: {
|
|
869
|
+
'x-api-key': key,
|
|
870
|
+
'anthropic-version': '2023-06-01',
|
|
871
|
+
'Content-Type': 'application/json',
|
|
872
|
+
},
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
const content = response.data?.content?.[0]?.text ?? '';
|
|
876
|
+
const u = response.data?.usage;
|
|
877
|
+
|
|
878
|
+
return {
|
|
879
|
+
content,
|
|
880
|
+
usage: u
|
|
881
|
+
? {
|
|
882
|
+
input: u.input_tokens ?? 0,
|
|
883
|
+
output: u.output_tokens ?? 0,
|
|
884
|
+
total: (u.input_tokens ?? 0) + (u.output_tokens ?? 0),
|
|
885
|
+
}
|
|
886
|
+
: undefined,
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
753
890
|
private async createOpenAiAssistant({
|
|
754
891
|
slug,
|
|
755
892
|
model,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { registerAiPrompts } from '../ai-instruction/ai-prompt-registry';
|
|
2
|
+
|
|
3
|
+
export const RICHTEXT_AI_PROMPT_SLUGS = {
|
|
4
|
+
editHtmlSystem: 'task.core.richtext-html.edit.system',
|
|
5
|
+
editHtmlUser: 'task.core.richtext-html.edit.user',
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
const EDIT_HTML_SYSTEM_PROMPT = `Você é um editor especialista em HTML de conteúdo administrativo. Sua tarefa é ajustar o HTML atual de um editor de texto rico seguindo a instrução de um administrador autenticado.
|
|
9
|
+
|
|
10
|
+
REGRAS:
|
|
11
|
+
1. Responda com o HTML completo e final do conteúdo, e NADA MAIS: sem cercas de código (\`\`\`), sem markdown, sem comentários ou explicações antes ou depois.
|
|
12
|
+
2. Faça APENAS o ajuste pedido na instrução. Preserve todo o resto do HTML (estrutura, textos, estilos, imagens, links) exatamente como estava.
|
|
13
|
+
3. Use apenas tags e formatação compatíveis com um editor de texto rico comum (parágrafos, títulos, negrito, itálico, sublinhado, listas, links, imagens) — nada de \`<script>\`, \`<style>\` externo ou recursos que o editor não consiga exibir.
|
|
14
|
+
4. Se o HTML de entrada estiver vazio, gere um HTML simples e razoável que atenda à instrução.`;
|
|
15
|
+
|
|
16
|
+
const EDIT_HTML_USER_PROMPT = `HTML ATUAL DO CONTEÚDO
|
|
17
|
+
<<<HTML
|
|
18
|
+
{{currentHtml}}
|
|
19
|
+
HTML>>>
|
|
20
|
+
|
|
21
|
+
INSTRUÇÃO DO ADMINISTRADOR
|
|
22
|
+
<<<INSTRUCAO
|
|
23
|
+
{{instruction}}
|
|
24
|
+
INSTRUCAO>>>
|
|
25
|
+
|
|
26
|
+
Responda apenas com o HTML completo e atualizado.`;
|
|
27
|
+
|
|
28
|
+
registerAiPrompts([
|
|
29
|
+
{
|
|
30
|
+
slug: RICHTEXT_AI_PROMPT_SLUGS.editHtmlSystem,
|
|
31
|
+
name: 'Ajuste de HTML do editor de texto rico por IA (sistema)',
|
|
32
|
+
moduleSlug: 'core',
|
|
33
|
+
locale: 'pt',
|
|
34
|
+
fallback: EDIT_HTML_SYSTEM_PROMPT,
|
|
35
|
+
variables: {},
|
|
36
|
+
defaults: { temperature: 0.3, maxTokens: 8000 },
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
slug: RICHTEXT_AI_PROMPT_SLUGS.editHtmlUser,
|
|
40
|
+
name: 'Ajuste de HTML do editor de texto rico por IA (usuário)',
|
|
41
|
+
moduleSlug: 'core',
|
|
42
|
+
locale: 'pt',
|
|
43
|
+
fallback: EDIT_HTML_USER_PROMPT,
|
|
44
|
+
variables: {
|
|
45
|
+
currentHtml: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
required: true,
|
|
48
|
+
description: 'HTML atual do conteúdo do editor (pode estar vazio).',
|
|
49
|
+
},
|
|
50
|
+
instruction: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
required: true,
|
|
53
|
+
description: 'Instrução em linguagem natural pedida pelo administrador.',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BadRequestException,
|
|
3
|
+
forwardRef,
|
|
4
|
+
Inject,
|
|
5
|
+
Injectable,
|
|
6
|
+
} from '@nestjs/common';
|
|
7
|
+
import { SettingService } from '../setting/setting.service';
|
|
8
|
+
import { AiService } from './ai.service';
|
|
9
|
+
import { RICHTEXT_AI_PROMPT_SLUGS } from './richtext-ai.prompts';
|
|
10
|
+
|
|
11
|
+
/** HTML maior que isso é documento inteiro, não um trecho de conteúdo — evita custo/contexto sem sentido. */
|
|
12
|
+
const MAX_HTML_CHARS = 60_000;
|
|
13
|
+
|
|
14
|
+
/** Instrução maior que isso é um briefing, não um ajuste pontual. */
|
|
15
|
+
const MAX_INSTRUCTION_CHARS = 2_000;
|
|
16
|
+
|
|
17
|
+
export type RichtextAiEditResult = {
|
|
18
|
+
html: string;
|
|
19
|
+
provider: string;
|
|
20
|
+
model: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Ajusta o HTML do editor de texto rico compartilhado do admin
|
|
25
|
+
* (`apps/admin/src/components/rich-text-editor.tsx`) a partir de um prompt em
|
|
26
|
+
* linguagem natural.
|
|
27
|
+
*
|
|
28
|
+
* Todo o trabalho pesado (multi-provider, prompts com override no banco,
|
|
29
|
+
* registro de custo em `ai_execution`) é do `AiService` do core — aqui só se
|
|
30
|
+
* lê a setting `richtext-ai-*` e se monta o contexto. Não persiste nada: quem
|
|
31
|
+
* decide salvar o HTML devolvido é o próprio editor, via `onChange`.
|
|
32
|
+
*/
|
|
33
|
+
@Injectable()
|
|
34
|
+
export class RichtextAiService {
|
|
35
|
+
constructor(
|
|
36
|
+
@Inject(forwardRef(() => SettingService))
|
|
37
|
+
private readonly settings: SettingService,
|
|
38
|
+
@Inject(forwardRef(() => AiService))
|
|
39
|
+
private readonly ai: AiService,
|
|
40
|
+
) {}
|
|
41
|
+
|
|
42
|
+
async editHtml(
|
|
43
|
+
input: { html?: string | null; instruction?: string | null },
|
|
44
|
+
): Promise<RichtextAiEditResult> {
|
|
45
|
+
const config = await this.getAiConfig();
|
|
46
|
+
|
|
47
|
+
if (!config.enabled) {
|
|
48
|
+
throw new BadRequestException(
|
|
49
|
+
'AI rich text editing is disabled. Enable it in Settings → AI.',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (!config.profileSlug) {
|
|
53
|
+
throw new BadRequestException(
|
|
54
|
+
'No AI profile configured for the rich text editor. Set one in Settings → AI.',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const instruction = String(input.instruction ?? '')
|
|
59
|
+
.trim()
|
|
60
|
+
.slice(0, MAX_INSTRUCTION_CHARS);
|
|
61
|
+
if (!instruction) {
|
|
62
|
+
throw new BadRequestException('Instruction is required.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const currentHtml = String(input.html ?? '').slice(0, MAX_HTML_CHARS);
|
|
66
|
+
|
|
67
|
+
const result = await this.ai.chatWithPrompt({
|
|
68
|
+
systemPromptSlug: RICHTEXT_AI_PROMPT_SLUGS.editHtmlSystem,
|
|
69
|
+
userPromptSlug: RICHTEXT_AI_PROMPT_SLUGS.editHtmlUser,
|
|
70
|
+
variables: { currentHtml, instruction },
|
|
71
|
+
profileSlug: config.profileSlug,
|
|
72
|
+
contextSlug: 'richtext.edit-html',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const html = this.extractHtml(result.content);
|
|
76
|
+
if (!html) {
|
|
77
|
+
throw new BadRequestException('The model returned an empty HTML.');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { html, provider: result.provider, model: result.model };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async getAiConfig(): Promise<{
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
profileSlug: string | null;
|
|
86
|
+
}> {
|
|
87
|
+
const slugs = ['richtext-ai-enabled', 'richtext-ai-profile-id'];
|
|
88
|
+
const values = await this.settings.getSettingValues(slugs);
|
|
89
|
+
|
|
90
|
+
const enabled = ['true', '1'].includes(
|
|
91
|
+
String(values['richtext-ai-enabled'] ?? '').trim().toLowerCase(),
|
|
92
|
+
);
|
|
93
|
+
const profileSlug =
|
|
94
|
+
String(values['richtext-ai-profile-id'] ?? '').trim() || null;
|
|
95
|
+
|
|
96
|
+
return { enabled, profileSlug };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* O prompt de sistema já pede HTML puro, mas alguns modelos insistem em
|
|
101
|
+
* cercar a resposta com ```html ... ``` mesmo assim. Remove a cerca quando
|
|
102
|
+
* presente para não gravar markdown como se fosse o conteúdo.
|
|
103
|
+
*/
|
|
104
|
+
private extractHtml(content: string): string {
|
|
105
|
+
const trimmed = content.trim();
|
|
106
|
+
const fenced = /^```(?:html)?\s*([\s\S]*?)\s*```$/i.exec(trimmed);
|
|
107
|
+
return (fenced ? fenced[1] : trimmed).trim();
|
|
108
|
+
}
|
|
109
|
+
}
|