@hed-hog/core 0.0.387 → 0.0.390
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 +12 -11
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
- package/dist/access-log/access-log.interceptor.js +4 -2
- package/dist/access-log/access-log.interceptor.js.map +1 -1
- package/dist/ai/ai-attachment.fragments.d.ts +23 -0
- package/dist/ai/ai-attachment.fragments.d.ts.map +1 -0
- package/dist/ai/ai-attachment.fragments.js +34 -0
- package/dist/ai/ai-attachment.fragments.js.map +1 -0
- package/dist/ai/ai.controller.d.ts +7 -16
- package/dist/ai/ai.controller.d.ts.map +1 -1
- package/dist/ai/ai.prompts.d.ts +16 -0
- package/dist/ai/ai.prompts.d.ts.map +1 -0
- package/dist/ai/ai.prompts.js +37 -0
- package/dist/ai/ai.prompts.js.map +1 -0
- package/dist/ai/ai.service.d.ts +63 -12
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +215 -88
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai/dto/chat.dto.d.ts +4 -1
- package/dist/ai/dto/chat.dto.d.ts.map +1 -1
- package/dist/ai/dto/chat.dto.js +23 -1
- package/dist/ai/dto/chat.dto.js.map +1 -1
- package/dist/ai/dto/create-agent.dto.d.ts +1 -1
- package/dist/ai/dto/create-agent.dto.d.ts.map +1 -1
- package/dist/ai/dto/create-agent.dto.js +1 -1
- package/dist/ai/dto/create-agent.dto.js.map +1 -1
- package/dist/ai/dto/update-agent.dto.d.ts +1 -1
- package/dist/ai/dto/update-agent.dto.d.ts.map +1 -1
- package/dist/ai/dto/update-agent.dto.js +1 -1
- package/dist/ai/dto/update-agent.dto.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.controller.d.ts +61 -7
- package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.controller.js +63 -20
- package/dist/ai-instruction/ai-instruction.controller.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.module.js +13 -2
- package/dist/ai-instruction/ai-instruction.module.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.d.ts +131 -6
- package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.js +533 -60
- package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts +8 -0
- package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-prompt-builder.service.js +10 -1
- package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -1
- package/dist/ai-instruction/ai-prompt-registry.d.ts +45 -0
- package/dist/ai-instruction/ai-prompt-registry.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-registry.js +49 -0
- package/dist/ai-instruction/ai-prompt-registry.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +89 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.js +222 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-template.util.d.ts +70 -0
- package/dist/ai-instruction/ai-prompt-template.util.d.ts.map +1 -0
- package/dist/ai-instruction/ai-prompt-template.util.js +154 -0
- package/dist/ai-instruction/ai-prompt-template.util.js.map +1 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +5 -0
- package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -1
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js +27 -1
- package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -1
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts +14 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts.map +1 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.js +42 -0
- package/dist/ai-instruction/dto/preview-ai-instruction.dto.js.map +1 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +11 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -1
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js +34 -0
- package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -1
- package/dist/ai-instruction/types/ai-instruction.types.d.ts +13 -1
- package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -1
- package/dist/ai-instruction/types/ai-instruction.types.js +10 -0
- package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -1
- package/dist/auth/auth.controller.d.ts +24 -9
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +49 -21
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts +33 -8
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +78 -29
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/captcha/captcha.module.d.ts +3 -0
- package/dist/captcha/captcha.module.d.ts.map +1 -0
- package/dist/captcha/captcha.module.js +23 -0
- package/dist/captcha/captcha.module.js.map +1 -0
- package/dist/captcha/captcha.service.d.ts +38 -0
- package/dist/captcha/captcha.service.d.ts.map +1 -0
- package/dist/captcha/captcha.service.js +144 -0
- package/dist/captcha/captcha.service.js.map +1 -0
- package/dist/challenge/challenge.service.d.ts +16 -7
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +64 -16
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core.module.d.ts +3 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +29 -2
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +15 -15
- package/dist/dashboard/dashboard/dashboard.service.d.ts +15 -15
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +6 -6
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +6 -6
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +20 -20
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +20 -20
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +13 -13
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +13 -13
- package/dist/file/file.service.d.ts +6 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +44 -4
- package/dist/file/file.service.js.map +1 -1
- package/dist/incident/incident-notifier.service.d.ts +36 -0
- package/dist/incident/incident-notifier.service.d.ts.map +1 -0
- package/dist/incident/incident-notifier.service.js +208 -0
- package/dist/incident/incident-notifier.service.js.map +1 -0
- package/dist/incident/incident.controller.d.ts +23 -0
- package/dist/incident/incident.controller.d.ts.map +1 -0
- package/dist/incident/incident.controller.js +75 -0
- package/dist/incident/incident.controller.js.map +1 -0
- package/dist/incident/incident.module.d.ts +7 -0
- package/dist/incident/incident.module.d.ts.map +1 -0
- package/dist/incident/incident.module.js +32 -0
- package/dist/incident/incident.module.js.map +1 -0
- package/dist/incident/incident.service.d.ts +72 -0
- package/dist/incident/incident.service.d.ts.map +1 -0
- package/dist/incident/incident.service.js +184 -0
- package/dist/incident/incident.service.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/dto/test.dto.d.ts +13 -0
- package/dist/integration-profile/dto/test.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/test.dto.js +26 -0
- package/dist/integration-profile/dto/test.dto.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +12 -1
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.controller.js +9 -1
- package/dist/integration-profile/integration-profile.controller.js.map +1 -1
- package/dist/integration-profile/integration-profile.module.d.ts +6 -1
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.module.js +26 -3
- package/dist/integration-profile/integration-profile.module.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.js +9 -1
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts +26 -7
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +94 -91
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.d.ts +13 -1
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +20 -5
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/integration-profile/testers/ai.testers.d.ts +3 -0
- package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/ai.testers.js +125 -0
- package/dist/integration-profile/testers/ai.testers.js.map +1 -0
- package/dist/integration-profile/testers/captcha.testers.d.ts +3 -0
- package/dist/integration-profile/testers/captcha.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/captcha.testers.js +121 -0
- package/dist/integration-profile/testers/captcha.testers.js.map +1 -0
- package/dist/integration-profile/testers/email.testers.d.ts +3 -0
- package/dist/integration-profile/testers/email.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/email.testers.js +128 -0
- package/dist/integration-profile/testers/email.testers.js.map +1 -0
- package/dist/integration-profile/testers/http-probe.d.ts +57 -0
- package/dist/integration-profile/testers/http-probe.d.ts.map +1 -0
- package/dist/integration-profile/testers/http-probe.js +140 -0
- package/dist/integration-profile/testers/http-probe.js.map +1 -0
- package/dist/integration-profile/testers/index.d.ts +12 -0
- package/dist/integration-profile/testers/index.d.ts.map +1 -0
- package/dist/integration-profile/testers/index.js +45 -0
- package/dist/integration-profile/testers/index.js.map +1 -0
- package/dist/integration-profile/testers/infrastructure.testers.d.ts +3 -0
- package/dist/integration-profile/testers/infrastructure.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/infrastructure.testers.js +105 -0
- package/dist/integration-profile/testers/infrastructure.testers.js.map +1 -0
- package/dist/integration-profile/testers/integration-tester.registry.d.ts +17 -0
- package/dist/integration-profile/testers/integration-tester.registry.d.ts.map +1 -0
- package/dist/integration-profile/testers/integration-tester.registry.js +52 -0
- package/dist/integration-profile/testers/integration-tester.registry.js.map +1 -0
- package/dist/integration-profile/testers/integration-tester.types.d.ts +55 -0
- package/dist/integration-profile/testers/integration-tester.types.d.ts.map +1 -0
- package/dist/integration-profile/testers/integration-tester.types.js +16 -0
- package/dist/integration-profile/testers/integration-tester.types.js.map +1 -0
- package/dist/integration-profile/testers/messaging.testers.d.ts +3 -0
- package/dist/integration-profile/testers/messaging.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/messaging.testers.js +70 -0
- package/dist/integration-profile/testers/messaging.testers.js.map +1 -0
- package/dist/integration-profile/testers/oauth.testers.d.ts +3 -0
- package/dist/integration-profile/testers/oauth.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/oauth.testers.js +285 -0
- package/dist/integration-profile/testers/oauth.testers.js.map +1 -0
- package/dist/integration-profile/testers/payment.testers.d.ts +3 -0
- package/dist/integration-profile/testers/payment.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/payment.testers.js +169 -0
- package/dist/integration-profile/testers/payment.testers.js.map +1 -0
- package/dist/integration-profile/testers/storage.testers.d.ts +3 -0
- package/dist/integration-profile/testers/storage.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/storage.testers.js +208 -0
- package/dist/integration-profile/testers/storage.testers.js.map +1 -0
- package/dist/language/en.json +4 -2
- package/dist/language/pt.json +4 -2
- package/dist/leaked-password/leaked-password.controller.d.ts +24 -0
- package/dist/leaked-password/leaked-password.controller.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.controller.js +78 -0
- package/dist/leaked-password/leaked-password.controller.js.map +1 -0
- package/dist/leaked-password/leaked-password.module.d.ts +8 -0
- package/dist/leaked-password/leaked-password.module.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.module.js +31 -0
- package/dist/leaked-password/leaked-password.module.js.map +1 -0
- package/dist/leaked-password/leaked-password.service.d.ts +64 -0
- package/dist/leaked-password/leaked-password.service.d.ts.map +1 -0
- package/dist/leaked-password/leaked-password.service.js +218 -0
- package/dist/leaked-password/leaked-password.service.js.map +1 -0
- package/dist/locale/locale.controller.d.ts +1 -1
- package/dist/locale/locale.service.d.ts +1 -1
- package/dist/mail/dto/preview.dto.d.ts +18 -0
- package/dist/mail/dto/preview.dto.d.ts.map +1 -0
- package/dist/mail/dto/preview.dto.js +66 -0
- package/dist/mail/dto/preview.dto.js.map +1 -0
- package/dist/mail/dto/send.dto.d.ts +7 -0
- 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 +4 -0
- package/dist/mail/mail.controller.d.ts.map +1 -1
- package/dist/mail/mail.controller.js +16 -2
- package/dist/mail/mail.controller.js.map +1 -1
- package/dist/mail/mail.service.d.ts +23 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +102 -13
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mail-layout/dto/update.dto.d.ts +17 -0
- package/dist/mail-layout/dto/update.dto.d.ts.map +1 -0
- package/dist/mail-layout/dto/update.dto.js +27 -0
- package/dist/mail-layout/dto/update.dto.js.map +1 -0
- package/dist/mail-layout/mail-layout.controller.d.ts +15 -0
- package/dist/mail-layout/mail-layout.controller.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.controller.js +71 -0
- package/dist/mail-layout/mail-layout.controller.js.map +1 -0
- package/dist/mail-layout/mail-layout.module.d.ts +3 -0
- package/dist/mail-layout/mail-layout.module.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.module.js +35 -0
- package/dist/mail-layout/mail-layout.module.js.map +1 -0
- package/dist/mail-layout/mail-layout.service.d.ts +27 -0
- package/dist/mail-layout/mail-layout.service.d.ts.map +1 -0
- package/dist/mail-layout/mail-layout.service.js +80 -0
- package/dist/mail-layout/mail-layout.service.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
- package/dist/mcp-chat/mcp-chat.service.d.ts +24 -2
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +80 -24
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/menu/menu.controller.d.ts +3 -3
- package/dist/menu/menu.service.d.ts +3 -3
- package/dist/notification/notification.controller.d.ts +12 -12
- package/dist/notification/notification.service.d.ts +12 -12
- package/dist/oauth/oauth-token-broker.service.d.ts +72 -0
- package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -0
- package/dist/oauth/oauth-token-broker.service.js +258 -0
- package/dist/oauth/oauth-token-broker.service.js.map +1 -0
- package/dist/oauth/oauth.module.d.ts.map +1 -1
- package/dist/oauth/oauth.module.js +3 -1
- package/dist/oauth/oauth.module.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +2 -0
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +6 -3
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/pdf/pdf.service.d.ts +8 -0
- package/dist/pdf/pdf.service.d.ts.map +1 -1
- package/dist/pdf/pdf.service.js +52 -0
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/presence/presence.controller.d.ts +16 -0
- package/dist/presence/presence.controller.d.ts.map +1 -0
- package/dist/presence/presence.controller.js +60 -0
- package/dist/presence/presence.controller.js.map +1 -0
- package/dist/presence/presence.listener.d.ts +29 -0
- package/dist/presence/presence.listener.d.ts.map +1 -0
- package/dist/presence/presence.listener.js +82 -0
- package/dist/presence/presence.listener.js.map +1 -0
- package/dist/presence/presence.module.d.ts +3 -0
- package/dist/presence/presence.module.d.ts.map +1 -0
- package/dist/presence/presence.module.js +32 -0
- package/dist/presence/presence.module.js.map +1 -0
- package/dist/presence/presence.service.d.ts +42 -0
- package/dist/presence/presence.service.d.ts.map +1 -0
- package/dist/presence/presence.service.js +147 -0
- package/dist/presence/presence.service.js.map +1 -0
- package/dist/profile/dto/delete-account.dto.d.ts +8 -0
- package/dist/profile/dto/delete-account.dto.d.ts.map +1 -0
- package/dist/profile/dto/delete-account.dto.js +22 -0
- package/dist/profile/dto/delete-account.dto.js.map +1 -0
- package/dist/profile/events/profile-account-deleted.event.d.ts +12 -0
- package/dist/profile/events/profile-account-deleted.event.d.ts.map +1 -0
- package/dist/profile/events/profile-account-deleted.event.js +17 -0
- package/dist/profile/events/profile-account-deleted.event.js.map +1 -0
- package/dist/profile/profile.controller.d.ts +21 -15
- package/dist/profile/profile.controller.d.ts.map +1 -1
- package/dist/profile/profile.controller.js +75 -46
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.service.d.ts +30 -18
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +113 -37
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/realtime/realtime.gateway.d.ts +48 -0
- package/dist/realtime/realtime.gateway.d.ts.map +1 -0
- package/dist/realtime/realtime.gateway.js +156 -0
- package/dist/realtime/realtime.gateway.js.map +1 -0
- package/dist/realtime/realtime.module.d.ts +8 -0
- package/dist/realtime/realtime.module.d.ts.map +1 -0
- package/dist/realtime/realtime.module.js +29 -0
- package/dist/realtime/realtime.module.js.map +1 -0
- package/dist/realtime/realtime.service.d.ts +51 -0
- package/dist/realtime/realtime.service.d.ts.map +1 -0
- package/dist/realtime/realtime.service.js +177 -0
- package/dist/realtime/realtime.service.js.map +1 -0
- package/dist/redis/redis-pubsub.d.ts +27 -0
- package/dist/redis/redis-pubsub.d.ts.map +1 -0
- package/dist/redis/redis-pubsub.js +140 -0
- package/dist/redis/redis-pubsub.js.map +1 -0
- package/dist/role/role.controller.d.ts +3 -3
- package/dist/role/role.service.d.ts +3 -3
- package/dist/setting/dto/create.dto.d.ts.map +1 -1
- package/dist/setting/dto/create.dto.js +9 -2
- package/dist/setting/dto/create.dto.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +5 -5
- package/dist/setting/setting.service.d.ts +8 -5
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +25 -1
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/dto/create-with-email-and-password.dto.d.ts +2 -0
- package/dist/user/dto/create-with-email-and-password.dto.d.ts.map +1 -1
- package/dist/user/dto/create-with-email-and-password.dto.js +5 -0
- package/dist/user/dto/create-with-email-and-password.dto.js.map +1 -1
- package/dist/user/dto/query-user-mail-list.dto.d.ts +5 -0
- package/dist/user/dto/query-user-mail-list.dto.d.ts.map +1 -0
- package/dist/user/dto/query-user-mail-list.dto.js +25 -0
- package/dist/user/dto/query-user-mail-list.dto.js.map +1 -0
- package/dist/user/user-credential.util.d.ts +19 -0
- package/dist/user/user-credential.util.d.ts.map +1 -0
- package/dist/user/user-credential.util.js +32 -0
- package/dist/user/user-credential.util.js.map +1 -0
- package/dist/user/user.controller.d.ts +17 -5
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +18 -3
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +28 -6
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +204 -13
- package/dist/user/user.service.js.map +1 -1
- package/dist/validators/is-strong-password-with-settings.validator.d.ts.map +1 -1
- package/dist/validators/is-strong-password-with-settings.validator.js +11 -0
- package/dist/validators/is-strong-password-with-settings.validator.js.map +1 -1
- package/dist/validators/service-locator.d.ts +9 -0
- package/dist/validators/service-locator.d.ts.map +1 -1
- package/dist/validators/service-locator.js +12 -0
- package/dist/validators/service-locator.js.map +1 -1
- package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
- package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
- package/hedhog/data/integration_provider.yaml +16 -0
- package/hedhog/data/mail.yaml +88 -61
- package/hedhog/data/mail_layout.yaml +188 -0
- package/hedhog/data/menu.yaml +67 -3
- package/hedhog/data/route.yaml +135 -0
- package/hedhog/data/setting_group.yaml +139 -1
- package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
- package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
- package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
- package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
- package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
- package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
- package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
- package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
- package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
- package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
- package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +153 -84
- package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
- package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
- package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
- package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
- package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
- package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
- package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
- package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
- package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
- package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
- package/hedhog/frontend/messages/en.json +499 -3
- package/hedhog/frontend/messages/pt.json +499 -3
- package/hedhog/table/ai_agent.yaml +1 -0
- package/hedhog/table/ai_instruction.yaml +15 -0
- package/hedhog/table/leaked_password.yaml +18 -0
- package/hedhog/table/mail_layout.yaml +35 -0
- package/hedhog/table/mail_var.yaml +4 -0
- package/hedhog/table/setting.yaml +1 -0
- package/hedhog/table/system_incident.yaml +59 -0
- package/hedhog/table/user_presence.yaml +36 -0
- package/package.json +8 -4
- package/src/access-log/access-log.interceptor.ts +4 -2
- package/src/ai/ai-attachment.fragments.spec.ts +319 -0
- package/src/ai/ai-attachment.fragments.ts +35 -0
- package/src/ai/ai.prompts.ts +38 -0
- package/src/ai/ai.service.spec.ts +280 -0
- package/src/ai/ai.service.ts +338 -82
- package/src/ai/dto/chat.dto.ts +33 -3
- package/src/ai/dto/create-agent.dto.ts +2 -2
- package/src/ai/dto/update-agent.dto.ts +2 -2
- package/src/ai-instruction/ai-instruction.controller.ts +40 -9
- package/src/ai-instruction/ai-instruction.module.ts +13 -2
- package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
- package/src/ai-instruction/ai-instruction.service.ts +661 -62
- package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
- package/src/ai-instruction/ai-prompt-registry.ts +87 -0
- package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
- package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
- package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
- package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
- package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
- package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
- package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
- package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
- package/src/auth/auth.controller.ts +31 -5
- package/src/auth/auth.service.spec.ts +3 -1
- package/src/auth/auth.service.ts +101 -36
- package/src/captcha/captcha.module.ts +10 -0
- package/src/captcha/captcha.service.spec.ts +210 -0
- package/src/captcha/captcha.service.ts +191 -0
- package/src/challenge/challenge.service.spec.ts +39 -4
- package/src/challenge/challenge.service.ts +72 -17
- package/src/core.module.ts +27 -1
- package/src/file/file.service.spec.ts +105 -0
- package/src/file/file.service.ts +60 -3
- package/src/incident/incident-notifier.service.spec.ts +205 -0
- package/src/incident/incident-notifier.service.ts +241 -0
- package/src/incident/incident.controller.ts +38 -0
- package/src/incident/incident.module.ts +19 -0
- package/src/incident/incident.service.spec.ts +150 -0
- package/src/incident/incident.service.ts +209 -0
- package/src/index.ts +37 -0
- package/src/integration-profile/dto/test.dto.ts +19 -0
- package/src/integration-profile/integration-profile.controller.ts +10 -1
- package/src/integration-profile/integration-profile.module.spec.ts +51 -0
- package/src/integration-profile/integration-profile.module.ts +23 -4
- package/src/integration-profile/integration-profile.secrets.ts +9 -1
- package/src/integration-profile/integration-profile.service.spec.ts +279 -0
- package/src/integration-profile/integration-profile.service.ts +120 -124
- package/src/integration-profile/integration-profile.utils.spec.ts +22 -0
- package/src/integration-profile/integration-profile.utils.ts +40 -3
- package/src/integration-profile/testers/ai.testers.ts +165 -0
- package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
- package/src/integration-profile/testers/captcha.testers.ts +139 -0
- package/src/integration-profile/testers/email.testers.ts +161 -0
- package/src/integration-profile/testers/http-probe.spec.ts +153 -0
- package/src/integration-profile/testers/http-probe.ts +171 -0
- package/src/integration-profile/testers/index.ts +30 -0
- package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
- package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
- package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
- package/src/integration-profile/testers/integration-tester.types.ts +61 -0
- package/src/integration-profile/testers/messaging.testers.ts +102 -0
- package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
- package/src/integration-profile/testers/oauth.testers.ts +305 -0
- package/src/integration-profile/testers/payment.testers.ts +185 -0
- package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
- package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
- package/src/integration-profile/testers/storage.testers.ts +226 -0
- package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
- package/src/language/en.json +4 -2
- package/src/language/pt.json +4 -2
- package/src/leaked-password/README.md +83 -0
- package/src/leaked-password/leaked-password.controller.ts +52 -0
- package/src/leaked-password/leaked-password.module.ts +18 -0
- package/src/leaked-password/leaked-password.service.ts +242 -0
- package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
- package/src/leaked-password/seed/common-passwords.txt +335 -0
- package/src/mail/dto/preview.dto.ts +50 -0
- package/src/mail/dto/send.dto.ts +14 -1
- package/src/mail/mail-template.spec.ts +197 -0
- package/src/mail/mail.controller.ts +9 -2
- package/src/mail/mail.service.spec.ts +116 -1
- package/src/mail/mail.service.ts +118 -12
- package/src/mail-layout/dto/update.dto.ts +19 -0
- package/src/mail-layout/mail-layout.controller.ts +47 -0
- package/src/mail-layout/mail-layout.module.ts +22 -0
- package/src/mail-layout/mail-layout.service.ts +94 -0
- package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
- package/src/mcp-chat/mcp-chat.service.ts +122 -26
- package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
- package/src/oauth/oauth-token-broker.service.ts +363 -0
- package/src/oauth/oauth.module.ts +3 -1
- package/src/oauth/oauth.service.ts +8 -2
- package/src/pdf/pdf.service.ts +75 -0
- package/src/presence/presence.controller.ts +29 -0
- package/src/presence/presence.listener.ts +53 -0
- package/src/presence/presence.module.ts +19 -0
- package/src/presence/presence.service.spec.ts +97 -0
- package/src/presence/presence.service.ts +160 -0
- package/src/profile/dto/delete-account.dto.ts +11 -0
- package/src/profile/events/profile-account-deleted.event.ts +13 -0
- package/src/profile/profile.controller.ts +46 -34
- package/src/profile/profile.service.ts +138 -38
- package/src/realtime/realtime.gateway.ts +138 -0
- package/src/realtime/realtime.module.ts +16 -0
- package/src/realtime/realtime.service.spec.ts +50 -0
- package/src/realtime/realtime.service.ts +187 -0
- package/src/redis/redis-pubsub.ts +179 -0
- package/src/setting/dto/create.dto.ts +13 -2
- package/src/setting/setting.service.spec.ts +56 -0
- package/src/setting/setting.service.ts +29 -1
- package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
- package/src/user/dto/query-user-mail-list.dto.ts +10 -0
- package/src/user/user-credential.util.ts +35 -0
- package/src/user/user.controller.ts +17 -2
- package/src/user/user.service.spec.ts +153 -0
- package/src/user/user.service.ts +255 -12
- package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
- package/src/validators/service-locator.ts +15 -0
- package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
- package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
|
@@ -5,22 +5,26 @@ import {
|
|
|
5
5
|
BadRequestException,
|
|
6
6
|
Inject,
|
|
7
7
|
Injectable,
|
|
8
|
+
Logger,
|
|
8
9
|
NotFoundException,
|
|
9
10
|
forwardRef,
|
|
10
11
|
} from '@nestjs/common';
|
|
11
12
|
import * as pako from 'pako';
|
|
12
|
-
import {
|
|
13
|
-
buildMailConfigFromIntegration,
|
|
14
|
-
buildWhatsappOfficialConfigFromIntegration,
|
|
15
|
-
} from './integration-profile.utils';
|
|
16
13
|
import { CreateDTO } from './dto/create.dto';
|
|
17
14
|
import {
|
|
18
15
|
ConflictResolutionDTO,
|
|
19
16
|
ImportProfileItemDTO,
|
|
20
17
|
} from './dto/import-confirm.dto';
|
|
18
|
+
import { TestDTO } from './dto/test.dto';
|
|
21
19
|
import { UpdateDTO } from './dto/update.dto';
|
|
22
20
|
import { IntegrationCredentialCryptoService } from './integration-credential-crypto.service';
|
|
23
21
|
import { getSensitiveConfigKeys } from './integration-profile.secrets';
|
|
22
|
+
import { sanitizeTesterError } from './testers/http-probe';
|
|
23
|
+
import { IntegrationTesterRegistry } from './testers/integration-tester.registry';
|
|
24
|
+
import {
|
|
25
|
+
INTEGRATION_TEST_TIMEOUT_MS,
|
|
26
|
+
IntegrationTestOutcome,
|
|
27
|
+
} from './testers/integration-tester.types';
|
|
24
28
|
|
|
25
29
|
type IntegrationProfileExportItem = {
|
|
26
30
|
slug: string;
|
|
@@ -58,6 +62,8 @@ type InvalidImportItem = {
|
|
|
58
62
|
|
|
59
63
|
@Injectable()
|
|
60
64
|
export class IntegrationProfileService {
|
|
65
|
+
private readonly logger = new Logger(IntegrationProfileService.name);
|
|
66
|
+
|
|
61
67
|
constructor(
|
|
62
68
|
@Inject(forwardRef(() => PrismaService))
|
|
63
69
|
private readonly prismaService: PrismaService,
|
|
@@ -65,6 +71,8 @@ export class IntegrationProfileService {
|
|
|
65
71
|
private readonly paginationService: PaginationService,
|
|
66
72
|
@Inject(forwardRef(() => IntegrationCredentialCryptoService))
|
|
67
73
|
private readonly credentialCrypto: IntegrationCredentialCryptoService,
|
|
74
|
+
@Inject(forwardRef(() => IntegrationTesterRegistry))
|
|
75
|
+
private readonly testerRegistry: IntegrationTesterRegistry,
|
|
68
76
|
) {}
|
|
69
77
|
|
|
70
78
|
async listTypes() {
|
|
@@ -433,7 +441,14 @@ export class IntegrationProfileService {
|
|
|
433
441
|
});
|
|
434
442
|
}
|
|
435
443
|
|
|
436
|
-
|
|
444
|
+
/**
|
|
445
|
+
* Testa as credenciais de um perfil contra o serviço real, sem salvar.
|
|
446
|
+
*
|
|
447
|
+
* Só despacha: quem sabe falar com cada provider é o `IntegrationTester` registrado
|
|
448
|
+
* no `IntegrationTesterRegistry`. Funciona tanto na edição (herda os segredos
|
|
449
|
+
* armazenados no lugar da máscara) quanto na criação de um perfil ainda inexistente.
|
|
450
|
+
*/
|
|
451
|
+
async test(data: TestDTO) {
|
|
437
452
|
await this.validateTypeAndProvider(data.type_id, data.provider_id);
|
|
438
453
|
|
|
439
454
|
const provider = await this.prismaService.integration_provider.findUnique({
|
|
@@ -455,17 +470,21 @@ export class IntegrationProfileService {
|
|
|
455
470
|
}
|
|
456
471
|
|
|
457
472
|
const typeSlug = provider.integration_type.slug;
|
|
458
|
-
|
|
473
|
+
const slug = data.slug.trim();
|
|
474
|
+
|
|
475
|
+
const tester = this.testerRegistry.find(provider.slug);
|
|
476
|
+
if (!tester) {
|
|
459
477
|
throw new BadRequestException(
|
|
460
|
-
|
|
478
|
+
`Connection test is not available for provider "${provider.slug}".`,
|
|
461
479
|
);
|
|
462
480
|
}
|
|
463
481
|
|
|
464
482
|
// "Deixe em branco para manter": ao testar na edição, herda os segredos já
|
|
465
483
|
// armazenados (decifrados pelo middleware) para os campos vazios/mascarados.
|
|
484
|
+
// Resolve por id quando ele veio: o slug é editável e pode ter mudado no form.
|
|
466
485
|
let effectiveConfig = (data.config as Record<string, unknown>) ?? null;
|
|
467
486
|
const stored = await this.prismaService.integration_profile.findUnique({
|
|
468
|
-
where: {
|
|
487
|
+
where: data.profile_id ? { id: data.profile_id } : { slug },
|
|
469
488
|
select: { config: true },
|
|
470
489
|
});
|
|
471
490
|
if (stored?.config) {
|
|
@@ -476,143 +495,120 @@ export class IntegrationProfileService {
|
|
|
476
495
|
) as Record<string, unknown>;
|
|
477
496
|
}
|
|
478
497
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
effectiveConfig,
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Resend não usa SMTP/from_email: valida credenciais/domínio próprios.
|
|
488
|
-
if (provider.slug === 'resend') {
|
|
489
|
-
const resendCfg = (effectiveConfig as Record<string, unknown> | null) ?? {};
|
|
490
|
-
const apiToken = String(resendCfg.api_token ?? '').trim();
|
|
491
|
-
const domain = String(resendCfg.domain ?? '').trim();
|
|
498
|
+
const config = effectiveConfig ?? {};
|
|
499
|
+
const secretValues = getSensitiveConfigKeys(provider.slug)
|
|
500
|
+
.map((key) => String(config[key] ?? ''))
|
|
501
|
+
.filter((value) => value.length > 0);
|
|
492
502
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
+
const timeoutMs = tester.timeoutMs ?? INTEGRATION_TEST_TIMEOUT_MS;
|
|
504
|
+
let outcome: IntegrationTestOutcome;
|
|
505
|
+
try {
|
|
506
|
+
// Duplo guarda de tempo: o AbortSignal cobre quem o respeita (fetch/SDKs) e o
|
|
507
|
+
// race cobre quem não respeita (o transporter do nodemailer, por exemplo).
|
|
508
|
+
outcome = await Promise.race([
|
|
509
|
+
tester.test(config, {
|
|
510
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
511
|
+
typeSlug,
|
|
512
|
+
providerSlug: provider.slug,
|
|
513
|
+
secretValues,
|
|
514
|
+
}),
|
|
515
|
+
this.hardTimeout(timeoutMs + 2_000),
|
|
516
|
+
]);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
outcome = {
|
|
519
|
+
ok: false,
|
|
520
|
+
error: sanitizeTesterError(error, secretValues),
|
|
503
521
|
};
|
|
504
522
|
}
|
|
505
523
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
)
|
|
524
|
+
const persisted = await this.recordValidation(
|
|
525
|
+
provider.slug,
|
|
526
|
+
slug,
|
|
527
|
+
outcome,
|
|
528
|
+
data.profile_id,
|
|
529
|
+
);
|
|
512
530
|
|
|
513
|
-
if (!
|
|
514
|
-
|
|
531
|
+
if (!outcome.ok) {
|
|
532
|
+
this.logger.warn(
|
|
533
|
+
`Integration test failed for provider "${provider.slug}" (profile "${slug}"): ${outcome.error}`,
|
|
534
|
+
);
|
|
535
|
+
throw new BadRequestException(outcome.error || 'Connection test failed.');
|
|
515
536
|
}
|
|
516
537
|
|
|
517
538
|
return {
|
|
539
|
+
// `success` e `destination` são o contrato legado consumido pela tela de
|
|
540
|
+
// e-mail (core/integrations-webhooks): mantidos com o mesmo significado.
|
|
518
541
|
success: true,
|
|
519
|
-
destination,
|
|
542
|
+
destination: String(config.from_email ?? '').trim() || outcome.info || '',
|
|
543
|
+
ok: true,
|
|
544
|
+
provider: provider.slug,
|
|
545
|
+
...(outcome.info ? { info: outcome.info } : {}),
|
|
546
|
+
...(outcome.warning ? { warning: outcome.warning } : {}),
|
|
547
|
+
tested_at: new Date().toISOString(),
|
|
548
|
+
persisted,
|
|
520
549
|
};
|
|
521
550
|
}
|
|
522
551
|
|
|
552
|
+
/** Rejeita depois de `ms`, para o caso de um tester ignorar o AbortSignal. */
|
|
553
|
+
private hardTimeout(ms: number): Promise<never> {
|
|
554
|
+
return new Promise((_resolve, reject) => {
|
|
555
|
+
const timer = setTimeout(() => {
|
|
556
|
+
const error = new Error('Connection test timed out.');
|
|
557
|
+
error.name = 'TimeoutError';
|
|
558
|
+
reject(error);
|
|
559
|
+
}, ms);
|
|
560
|
+
// Não segura o processo vivo caso o teste termine antes.
|
|
561
|
+
timer.unref?.();
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
523
565
|
/**
|
|
524
|
-
*
|
|
525
|
-
*
|
|
566
|
+
* Grava metadados (não-secretos) da última validação no config do perfil.
|
|
567
|
+
*
|
|
568
|
+
* Devolve se gravou: no fluxo de criação não existe linha ainda, e a UI usa isso
|
|
569
|
+
* para avisar que o resultado não ficou registrado.
|
|
526
570
|
*/
|
|
527
|
-
private async
|
|
571
|
+
private async recordValidation(
|
|
528
572
|
providerSlug: string,
|
|
529
573
|
slug: string,
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
throw new BadRequestException(
|
|
534
|
-
`Integration profile test is not available for provider "${providerSlug}".`,
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
const cfg = buildWhatsappOfficialConfigFromIntegration(effectiveConfig);
|
|
539
|
-
|
|
540
|
-
if (!cfg.accessToken) {
|
|
541
|
-
throw new BadRequestException('WhatsApp access token is required.');
|
|
542
|
-
}
|
|
543
|
-
if (!cfg.wabaId) {
|
|
544
|
-
throw new BadRequestException('WhatsApp Business Account ID is required.');
|
|
545
|
-
}
|
|
546
|
-
if (!cfg.appSecret) {
|
|
547
|
-
throw new BadRequestException(
|
|
548
|
-
'Meta App Secret is required to validate webhook signatures.',
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
if (!cfg.verifyToken) {
|
|
552
|
-
throw new BadRequestException('Webhook verify token is required.');
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const url = `https://graph.facebook.com/${cfg.graphApiVersion}/${encodeURIComponent(
|
|
556
|
-
cfg.wabaId,
|
|
557
|
-
)}?fields=id,name`;
|
|
558
|
-
|
|
559
|
-
let name = '';
|
|
560
|
-
let failure: string | null = null;
|
|
574
|
+
outcome: IntegrationTestOutcome,
|
|
575
|
+
profileId?: number,
|
|
576
|
+
): Promise<boolean> {
|
|
561
577
|
try {
|
|
562
|
-
const
|
|
563
|
-
|
|
578
|
+
const stored = await this.prismaService.integration_profile.findUnique({
|
|
579
|
+
where: profileId ? { id: profileId } : { slug },
|
|
580
|
+
select: { id: true, config: true },
|
|
564
581
|
});
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
582
|
+
// Perfil ainda não salvo (teste no fluxo de criação): nada a registrar.
|
|
583
|
+
if (!stored) return false;
|
|
584
|
+
|
|
585
|
+
// Parte de `stored.config`, NUNCA do config recebido: o que o usuário digitou
|
|
586
|
+
// e ainda não salvou não pode ser persistido de carona num teste.
|
|
587
|
+
// `stored.config` vem decifrado pelo middleware; recifra-mos ao gravar.
|
|
588
|
+
const plain = {
|
|
589
|
+
...((stored.config as Record<string, unknown>) ?? {}),
|
|
590
|
+
last_validated_at: new Date().toISOString(),
|
|
591
|
+
last_validation_status: outcome.ok ? 'ok' : 'error',
|
|
592
|
+
last_error: outcome.ok ? null : (outcome.error ?? null),
|
|
593
|
+
last_validation_info: outcome.ok ? (outcome.info ?? null) : null,
|
|
568
594
|
};
|
|
569
|
-
if (!response.ok) {
|
|
570
|
-
// A mensagem da Meta não contém o token; ainda assim só propagamos o texto dela.
|
|
571
|
-
failure =
|
|
572
|
-
body?.error?.message ?? `Graph API returned HTTP ${response.status}.`;
|
|
573
|
-
} else {
|
|
574
|
-
name = String(body?.name ?? '');
|
|
575
|
-
}
|
|
576
|
-
} catch (error) {
|
|
577
|
-
failure = error instanceof Error ? error.message : 'Graph API is unreachable.';
|
|
578
|
-
}
|
|
579
595
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
596
|
+
await this.prismaService.integration_profile.update({
|
|
597
|
+
where: { id: stored.id },
|
|
598
|
+
data: {
|
|
599
|
+
config: this.credentialCrypto.encryptConfig(providerSlug, plain) as object,
|
|
600
|
+
},
|
|
601
|
+
});
|
|
602
|
+
return true;
|
|
603
|
+
} catch (error) {
|
|
604
|
+
// Falhar ao REGISTRAR não pode transformar um teste bem-sucedido em erro 500.
|
|
605
|
+
this.logger.error(
|
|
606
|
+
`Failed to record validation for profile "${slug}": ${
|
|
607
|
+
error instanceof Error ? error.message : String(error)
|
|
608
|
+
}`,
|
|
609
|
+
);
|
|
610
|
+
return false;
|
|
584
611
|
}
|
|
585
|
-
|
|
586
|
-
return { success: true, destination: name || cfg.wabaId };
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/** Grava metadados (não-secretos) da última validação no config do perfil. */
|
|
590
|
-
private async recordWhatsappValidation(
|
|
591
|
-
providerSlug: string,
|
|
592
|
-
slug: string,
|
|
593
|
-
failure: string | null,
|
|
594
|
-
) {
|
|
595
|
-
const stored = await this.prismaService.integration_profile.findUnique({
|
|
596
|
-
where: { slug },
|
|
597
|
-
select: { id: true, config: true },
|
|
598
|
-
});
|
|
599
|
-
// Perfil ainda não salvo (teste no fluxo de criação): nada a registrar.
|
|
600
|
-
if (!stored) return;
|
|
601
|
-
|
|
602
|
-
// `stored.config` vem decifrado pelo middleware; recifra-mos ao gravar.
|
|
603
|
-
const plain = {
|
|
604
|
-
...((stored.config as Record<string, unknown>) ?? {}),
|
|
605
|
-
last_validated_at: new Date().toISOString(),
|
|
606
|
-
last_validation_status: failure ? 'error' : 'ok',
|
|
607
|
-
last_error: failure ?? null,
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
await this.prismaService.integration_profile.update({
|
|
611
|
-
where: { id: stored.id },
|
|
612
|
-
data: {
|
|
613
|
-
config: this.credentialCrypto.encryptConfig(providerSlug, plain) as object,
|
|
614
|
-
},
|
|
615
|
-
});
|
|
616
612
|
}
|
|
617
613
|
|
|
618
614
|
async exportProfiles({
|
|
@@ -325,6 +325,28 @@ describe('integration-profile.utils', () => {
|
|
|
325
325
|
});
|
|
326
326
|
});
|
|
327
327
|
|
|
328
|
+
it('mapeia deepseek com a base URL padrão', () => {
|
|
329
|
+
expect(
|
|
330
|
+
buildAiConfigFromIntegration('deepseek', {
|
|
331
|
+
api_key: 'd',
|
|
332
|
+
model: 'deepseek-reasoner',
|
|
333
|
+
}),
|
|
334
|
+
).toEqual({
|
|
335
|
+
apiKey: 'd',
|
|
336
|
+
model: 'deepseek-reasoner',
|
|
337
|
+
baseUrl: 'https://api.deepseek.com',
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('respeita a base URL informada no perfil deepseek', () => {
|
|
342
|
+
expect(
|
|
343
|
+
buildAiConfigFromIntegration('deepseek', {
|
|
344
|
+
api_key: 'd',
|
|
345
|
+
base_url: 'https://proxy.interno/v1/',
|
|
346
|
+
}),
|
|
347
|
+
).toEqual({ apiKey: 'd', baseUrl: 'https://proxy.interno/v1' });
|
|
348
|
+
});
|
|
349
|
+
|
|
328
350
|
it('lança para provider desconhecido', () => {
|
|
329
351
|
expect(() => buildAiConfigFromIntegration('llama', {})).toThrow(
|
|
330
352
|
BadRequestException,
|
|
@@ -300,21 +300,58 @@ export function buildKubernetesConfigFromIntegration(
|
|
|
300
300
|
|
|
301
301
|
// ─── AI utilities ─────────────────────────────────────────────────────────────
|
|
302
302
|
|
|
303
|
-
/**
|
|
303
|
+
/**
|
|
304
|
+
* Base URL da API do DeepSeek. A API é compatível com o formato OpenAI
|
|
305
|
+
* (`POST {base}/chat/completions`), então os consumidores reaproveitam o mesmo
|
|
306
|
+
* corpo de requisição trocando apenas a URL e a chave.
|
|
307
|
+
*/
|
|
308
|
+
export const DEEPSEEK_API_BASE_URL = 'https://api.deepseek.com';
|
|
309
|
+
|
|
310
|
+
/** Modelo usado quando o perfil DeepSeek não define um (`deepseek-reasoner` é o de raciocínio). */
|
|
311
|
+
export const DEEPSEEK_DEFAULT_MODEL = 'deepseek-chat';
|
|
312
|
+
|
|
313
|
+
/** Maps an integration_profile config JSON to the API key and optional org/model/timeout needed by AI providers. */
|
|
304
314
|
export function buildAiConfigFromIntegration(
|
|
305
315
|
providerSlug: string,
|
|
306
316
|
config: unknown,
|
|
307
|
-
): {
|
|
317
|
+
): {
|
|
318
|
+
apiKey: string;
|
|
319
|
+
organization?: string;
|
|
320
|
+
model?: string;
|
|
321
|
+
timeoutMs?: number;
|
|
322
|
+
/** Endpoint OpenAI-compatible do provider (hoje só o DeepSeek usa). */
|
|
323
|
+
baseUrl?: string;
|
|
324
|
+
} {
|
|
308
325
|
const cfg = (config as Cfg) ?? {};
|
|
326
|
+
const model = String(cfg.model ?? '').trim() || undefined;
|
|
327
|
+
const parsedTimeout = Number(cfg.timeout_ms);
|
|
328
|
+
const timeoutMs = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? parsedTimeout : undefined;
|
|
329
|
+
|
|
309
330
|
switch (providerSlug.toLowerCase()) {
|
|
310
331
|
case 'openai':
|
|
311
332
|
return {
|
|
312
333
|
apiKey: String(cfg.api_key ?? ''),
|
|
313
334
|
...(cfg.organization ? { organization: String(cfg.organization) } : {}),
|
|
335
|
+
...(model ? { model } : {}),
|
|
336
|
+
...(timeoutMs ? { timeoutMs } : {}),
|
|
337
|
+
};
|
|
338
|
+
case 'deepseek':
|
|
339
|
+
return {
|
|
340
|
+
apiKey: String(cfg.api_key ?? ''),
|
|
341
|
+
...(model ? { model } : {}),
|
|
342
|
+
...(timeoutMs ? { timeoutMs } : {}),
|
|
343
|
+
baseUrl:
|
|
344
|
+
String(cfg.base_url ?? '')
|
|
345
|
+
.trim()
|
|
346
|
+
.replace(/\/+$/, '') || DEEPSEEK_API_BASE_URL,
|
|
314
347
|
};
|
|
315
348
|
case 'gemini':
|
|
316
349
|
case 'claude':
|
|
317
|
-
return {
|
|
350
|
+
return {
|
|
351
|
+
apiKey: String(cfg.api_key ?? ''),
|
|
352
|
+
...(model ? { model } : {}),
|
|
353
|
+
...(timeoutMs ? { timeoutMs } : {}),
|
|
354
|
+
};
|
|
318
355
|
default:
|
|
319
356
|
throw new BadRequestException(`Unsupported AI provider: ${providerSlug}`);
|
|
320
357
|
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describeHttpError,
|
|
3
|
+
fail,
|
|
4
|
+
pass,
|
|
5
|
+
probeJson,
|
|
6
|
+
requireFields,
|
|
7
|
+
str,
|
|
8
|
+
} from './http-probe';
|
|
9
|
+
import { IntegrationTester } from './integration-tester.types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Testadores dos providers de IA e geração de vídeo.
|
|
13
|
+
*
|
|
14
|
+
* Todos listam modelos: é a chamada autenticada mais barata de cada API (não consome
|
|
15
|
+
* token nem gera cobrança) e prova que a chave está ativa.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const openAiTester: IntegrationTester = {
|
|
19
|
+
providerSlug: 'openai',
|
|
20
|
+
test: async (config, ctx) => {
|
|
21
|
+
const missing = requireFields(config, [['api_key', 'API key']]);
|
|
22
|
+
if (missing) return missing;
|
|
23
|
+
|
|
24
|
+
const organization = str(config, 'organization');
|
|
25
|
+
const headers: Record<string, string> = {
|
|
26
|
+
Authorization: `Bearer ${String(config.api_key ?? '')}`,
|
|
27
|
+
...(organization ? { 'OpenAI-Organization': organization } : {}),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const result = await probeJson(
|
|
31
|
+
'https://api.openai.com/v1/models',
|
|
32
|
+
{ headers },
|
|
33
|
+
ctx.signal,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (result.status === 401) return fail('Invalid OpenAI API key.');
|
|
37
|
+
if (result.status === 403) {
|
|
38
|
+
return fail('This API key has no permission to list models.');
|
|
39
|
+
}
|
|
40
|
+
if (!result.ok) {
|
|
41
|
+
return fail(describeHttpError(result, 'OpenAI rejected the credentials.'));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const models: Array<{ id?: string }> = Array.isArray(result.body?.data)
|
|
45
|
+
? result.body.data
|
|
46
|
+
: [];
|
|
47
|
+
const wanted = str(config, 'model');
|
|
48
|
+
|
|
49
|
+
// Modelo indisponível para a conta não invalida a chave — o operador só precisa
|
|
50
|
+
// saber antes de descobrir na primeira chamada real.
|
|
51
|
+
if (wanted && !models.some((model) => model.id === wanted)) {
|
|
52
|
+
return pass(
|
|
53
|
+
`OpenAI — ${models.length} model(s) available`,
|
|
54
|
+
`The model "${wanted}" is not available for this account.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return pass(
|
|
58
|
+
`OpenAI — ${models.length} model(s) available${wanted ? ` (${wanted} ok)` : ''}`,
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const geminiTester: IntegrationTester = {
|
|
64
|
+
providerSlug: 'gemini',
|
|
65
|
+
test: async (config, ctx) => {
|
|
66
|
+
const missing = requireFields(config, [['api_key', 'API key']]);
|
|
67
|
+
if (missing) return missing;
|
|
68
|
+
|
|
69
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(
|
|
70
|
+
String(config.api_key ?? ''),
|
|
71
|
+
)}`;
|
|
72
|
+
const result = await probeJson(url, {}, ctx.signal);
|
|
73
|
+
|
|
74
|
+
if (result.status === 400 || result.status === 401 || result.status === 403) {
|
|
75
|
+
return fail('Invalid Gemini API key.');
|
|
76
|
+
}
|
|
77
|
+
if (!result.ok) {
|
|
78
|
+
return fail(describeHttpError(result, 'Google rejected the credentials.'));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const models: unknown[] = Array.isArray(result.body?.models)
|
|
82
|
+
? result.body.models
|
|
83
|
+
: [];
|
|
84
|
+
return pass(`Gemini — ${models.length} model(s) available`);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const claudeTester: IntegrationTester = {
|
|
89
|
+
providerSlug: 'claude',
|
|
90
|
+
test: async (config, ctx) => {
|
|
91
|
+
const missing = requireFields(config, [['api_key', 'API key']]);
|
|
92
|
+
if (missing) return missing;
|
|
93
|
+
|
|
94
|
+
const result = await probeJson(
|
|
95
|
+
'https://api.anthropic.com/v1/models',
|
|
96
|
+
{
|
|
97
|
+
headers: {
|
|
98
|
+
'x-api-key': String(config.api_key ?? ''),
|
|
99
|
+
'anthropic-version': '2023-06-01',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
ctx.signal,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
if (result.status === 401) return fail('Invalid Anthropic API key.');
|
|
106
|
+
if (!result.ok) {
|
|
107
|
+
return fail(describeHttpError(result, 'Anthropic rejected the credentials.'));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const models: unknown[] = Array.isArray(result.body?.data) ? result.body.data : [];
|
|
111
|
+
return pass(`Claude — ${models.length} model(s) available`);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const deepseekTester: IntegrationTester = {
|
|
116
|
+
providerSlug: 'deepseek',
|
|
117
|
+
test: async (config, ctx) => {
|
|
118
|
+
const missing = requireFields(config, [['api_key', 'API key']]);
|
|
119
|
+
if (missing) return missing;
|
|
120
|
+
|
|
121
|
+
const result = await probeJson(
|
|
122
|
+
'https://api.deepseek.com/models',
|
|
123
|
+
{ headers: { Authorization: `Bearer ${String(config.api_key ?? '')}` } },
|
|
124
|
+
ctx.signal,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (result.status === 401) return fail('Invalid DeepSeek API key.');
|
|
128
|
+
if (!result.ok) {
|
|
129
|
+
return fail(describeHttpError(result, 'DeepSeek rejected the credentials.'));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const models: unknown[] = Array.isArray(result.body?.data) ? result.body.data : [];
|
|
133
|
+
return pass(`DeepSeek — ${models.length} model(s) available`);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const lumaTester: IntegrationTester = {
|
|
138
|
+
providerSlug: 'luma',
|
|
139
|
+
test: async (config, ctx) => {
|
|
140
|
+
const missing = requireFields(config, [['api_key', 'API key']]);
|
|
141
|
+
if (missing) return missing;
|
|
142
|
+
|
|
143
|
+
const result = await probeJson(
|
|
144
|
+
'https://api.lumalabs.ai/dream-machine/v1/generations?limit=1',
|
|
145
|
+
{ headers: { Authorization: `Bearer ${String(config.api_key ?? '')}` } },
|
|
146
|
+
ctx.signal,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (result.status === 401 || result.status === 403) {
|
|
150
|
+
return fail('Invalid Luma API key.');
|
|
151
|
+
}
|
|
152
|
+
if (!result.ok) {
|
|
153
|
+
return fail(describeHttpError(result, 'Luma rejected the credentials.'));
|
|
154
|
+
}
|
|
155
|
+
return pass('Luma Dream Machine');
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const AI_TESTERS: IntegrationTester[] = [
|
|
160
|
+
openAiTester,
|
|
161
|
+
geminiTester,
|
|
162
|
+
claudeTester,
|
|
163
|
+
deepseekTester,
|
|
164
|
+
lumaTester,
|
|
165
|
+
];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
|
|
2
|
+
import { CAPTCHA_TESTERS } from './captcha.testers';
|
|
3
|
+
import { IntegrationTestContext, IntegrationTester } from './integration-tester.types';
|
|
4
|
+
|
|
5
|
+
const bySlug = (slug: string): IntegrationTester =>
|
|
6
|
+
CAPTCHA_TESTERS.find((tester) => tester.providerSlug === slug)!;
|
|
7
|
+
|
|
8
|
+
const ctx = (): IntegrationTestContext => ({
|
|
9
|
+
signal: AbortSignal.timeout(5_000),
|
|
10
|
+
typeSlug: 'captcha',
|
|
11
|
+
providerSlug: 'test',
|
|
12
|
+
secretValues: [],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function siteverify(errorCodes: string[], success = false) {
|
|
16
|
+
return {
|
|
17
|
+
ok: true,
|
|
18
|
+
status: 200,
|
|
19
|
+
text: async () => JSON.stringify({ success, 'error-codes': errorCodes }),
|
|
20
|
+
} as unknown as Response;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let fetchMock: jest.Mock;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
fetchMock = jest.fn();
|
|
27
|
+
global.fetch = fetchMock as unknown as typeof fetch;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
jest.restoreAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe.each([
|
|
35
|
+
['recaptcha', 'Invalid reCAPTCHA secret key.'],
|
|
36
|
+
['cloudflare-turnstile', 'Invalid Turnstile secret key.'],
|
|
37
|
+
])('%s tester', (slug, invalidSecretMessage) => {
|
|
38
|
+
const tester = bySlug(slug);
|
|
39
|
+
|
|
40
|
+
it('reprova quando o siteverify recusa o segredo', async () => {
|
|
41
|
+
fetchMock.mockResolvedValue(siteverify(['invalid-input-secret']));
|
|
42
|
+
|
|
43
|
+
const outcome = await tester.test(
|
|
44
|
+
{ site_key: 'site', secret_key: 'wrong' },
|
|
45
|
+
ctx(),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(outcome).toEqual({ ok: false, error: invalidSecretMessage });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('aprova quando o siteverify aceita o segredo e só reclama do token de teste', async () => {
|
|
52
|
+
fetchMock.mockResolvedValue(
|
|
53
|
+
siteverify(['missing-input-response', 'invalid-input-response']),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const outcome = await tester.test(
|
|
57
|
+
{ site_key: 'site', secret_key: 'right' },
|
|
58
|
+
ctx(),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(outcome.ok).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('reprova sem ir à rede quando falta o segredo', async () => {
|
|
65
|
+
const outcome = await tester.test({ site_key: 'site' }, ctx());
|
|
66
|
+
|
|
67
|
+
expect(outcome.ok).toBe(false);
|
|
68
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('altcha tester', () => {
|
|
73
|
+
const tester = bySlug('altcha');
|
|
74
|
+
|
|
75
|
+
it('valida a chave localmente e avisa que não há verificação remota', async () => {
|
|
76
|
+
const outcome = await tester.test(
|
|
77
|
+
{ hmac_key: 'uma-chave-hmac-suficientemente-longa' },
|
|
78
|
+
ctx(),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(outcome.ok).toBe(true);
|
|
82
|
+
expect(outcome.warning).toContain('self-hosted');
|
|
83
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('reprova uma chave curta demais', async () => {
|
|
87
|
+
const outcome = await tester.test({ hmac_key: 'curta' }, ctx());
|
|
88
|
+
|
|
89
|
+
expect(outcome.ok).toBe(false);
|
|
90
|
+
expect(outcome.error).toContain('too short');
|
|
91
|
+
});
|
|
92
|
+
});
|