@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
# SHA-1 da senha em claro, 20 bytes. SHA-1 porque e o formato em que os corpus
|
|
4
|
+
# publicos de vazamento (Pwned Passwords) sao distribuidos — aqui ele e
|
|
5
|
+
# identificador de item de lista publica, nao protecao de senha. As senhas do
|
|
6
|
+
# sistema continuam em hash de senha proprio e as do cofre em Argon2id+AES-GCM.
|
|
7
|
+
- name: hash
|
|
8
|
+
type: bytes
|
|
9
|
+
isUnique: true
|
|
10
|
+
# Quantas vezes o hash apareceu nos vazamentos conhecidos, quando o dump
|
|
11
|
+
# informa. 0 = desconhecido (caso do seed base, que vem de lista curada).
|
|
12
|
+
- name: occurrences
|
|
13
|
+
type: int
|
|
14
|
+
default: 0
|
|
15
|
+
- type: created_at
|
|
16
|
+
|
|
17
|
+
indices:
|
|
18
|
+
- columns: [occurrences]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
- type: slug
|
|
4
|
+
- name: is_default
|
|
5
|
+
type: boolean
|
|
6
|
+
default: false
|
|
7
|
+
comment: "Layout applied to every mail that does not skip or override it"
|
|
8
|
+
- name: wrapper
|
|
9
|
+
type: text
|
|
10
|
+
comment: "Full HTML document with {{{header}}} / {{{content}}} / {{{footer}}} tokens. Structural (CSS) and therefore not translatable."
|
|
11
|
+
- name: name
|
|
12
|
+
type: locale_varchar
|
|
13
|
+
length: 255
|
|
14
|
+
locale:
|
|
15
|
+
en: Name
|
|
16
|
+
pt: Nome
|
|
17
|
+
- name: header
|
|
18
|
+
type: locale_text
|
|
19
|
+
isNullable: true
|
|
20
|
+
locale:
|
|
21
|
+
en: Header
|
|
22
|
+
pt: Cabeçalho
|
|
23
|
+
- name: footer
|
|
24
|
+
type: locale_text
|
|
25
|
+
isNullable: true
|
|
26
|
+
locale:
|
|
27
|
+
en: Footer
|
|
28
|
+
pt: Rodapé
|
|
29
|
+
- type: created_at
|
|
30
|
+
- type: updated_at
|
|
31
|
+
|
|
32
|
+
indices:
|
|
33
|
+
- columns: [is_default]
|
|
34
|
+
isUnique: true
|
|
35
|
+
where: is_default = true
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
columns:
|
|
2
|
+
- type: pk
|
|
3
|
+
# Origem no formato "<modulo>.<area>", ex.: core.mail, legacy.reconcile.
|
|
4
|
+
- name: source
|
|
5
|
+
type: varchar
|
|
6
|
+
length: 120
|
|
7
|
+
# Identificador estavel da falha, ex.: mail_send_failed.
|
|
8
|
+
- name: code
|
|
9
|
+
type: varchar
|
|
10
|
+
length: 120
|
|
11
|
+
- name: severity
|
|
12
|
+
type: enum
|
|
13
|
+
values:
|
|
14
|
+
- warning
|
|
15
|
+
- error
|
|
16
|
+
- critical
|
|
17
|
+
default: error
|
|
18
|
+
- name: message
|
|
19
|
+
type: text
|
|
20
|
+
- name: context
|
|
21
|
+
type: json
|
|
22
|
+
isNullable: true
|
|
23
|
+
# Hash de (source, code, chave de agrupamento). E o que impede uma falha
|
|
24
|
+
# repetitiva de virar milhares de linhas: repeticao vira contador.
|
|
25
|
+
- name: fingerprint
|
|
26
|
+
type: varchar
|
|
27
|
+
length: 64
|
|
28
|
+
isUnique: true
|
|
29
|
+
- name: occurrences
|
|
30
|
+
type: int
|
|
31
|
+
default: 1
|
|
32
|
+
- name: first_seen_at
|
|
33
|
+
type: datetime
|
|
34
|
+
- name: last_seen_at
|
|
35
|
+
type: datetime
|
|
36
|
+
# Ultima vez que este incidente gerou aviso; base do cooldown.
|
|
37
|
+
- name: notified_at
|
|
38
|
+
type: datetime
|
|
39
|
+
isNullable: true
|
|
40
|
+
- name: resolved_at
|
|
41
|
+
type: datetime
|
|
42
|
+
isNullable: true
|
|
43
|
+
- name: resolved_by
|
|
44
|
+
type: fk
|
|
45
|
+
isNullable: true
|
|
46
|
+
references:
|
|
47
|
+
table: user
|
|
48
|
+
column: id
|
|
49
|
+
onDelete: SET NULL
|
|
50
|
+
onUpdate: CASCADE
|
|
51
|
+
- type: created_at
|
|
52
|
+
- type: updated_at
|
|
53
|
+
|
|
54
|
+
indices:
|
|
55
|
+
- columns: [source]
|
|
56
|
+
- columns: [code]
|
|
57
|
+
- columns: [severity]
|
|
58
|
+
- columns: [resolved_at]
|
|
59
|
+
- columns: [last_seen_at]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Unified presence per user: app heartbeat (real-time, this application) merged
|
|
2
|
+
# with Microsoft Teams presence (when the Teams integration is configured). One
|
|
3
|
+
# row per user, upserted by the heartbeat endpoint and by the Microsoft presence
|
|
4
|
+
# processor.
|
|
5
|
+
columns:
|
|
6
|
+
- type: pk
|
|
7
|
+
- name: user_id
|
|
8
|
+
type: fk
|
|
9
|
+
references:
|
|
10
|
+
table: user
|
|
11
|
+
column: id
|
|
12
|
+
onDelete: CASCADE
|
|
13
|
+
onUpdate: CASCADE
|
|
14
|
+
# Last time the user's browser pinged the heartbeat endpoint (app presence).
|
|
15
|
+
- name: last_heartbeat_at
|
|
16
|
+
type: timestamptz
|
|
17
|
+
isNullable: true
|
|
18
|
+
# Latest Microsoft Teams presence (Available/Busy/Away/DoNotDisturb/Offline/...).
|
|
19
|
+
- name: teams_availability
|
|
20
|
+
type: varchar
|
|
21
|
+
length: 64
|
|
22
|
+
isNullable: true
|
|
23
|
+
- name: teams_activity
|
|
24
|
+
type: varchar
|
|
25
|
+
length: 64
|
|
26
|
+
isNullable: true
|
|
27
|
+
- name: teams_updated_at
|
|
28
|
+
type: timestamptz
|
|
29
|
+
isNullable: true
|
|
30
|
+
- type: created_at
|
|
31
|
+
- type: updated_at
|
|
32
|
+
|
|
33
|
+
indices:
|
|
34
|
+
- columns: [user_id]
|
|
35
|
+
isUnique: true
|
|
36
|
+
- columns: [last_heartbeat_at]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.390",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,8 +20,10 @@
|
|
|
20
20
|
"@nestjs/event-emitter": "*",
|
|
21
21
|
"@nestjs/jwt": "^11",
|
|
22
22
|
"@nestjs/mapped-types": "*",
|
|
23
|
+
"@nestjs/platform-socket.io": "^11",
|
|
23
24
|
"@nestjs/schedule": "^6.0.1",
|
|
24
25
|
"@nestjs/throttler": "^6.4.0",
|
|
26
|
+
"@nestjs/websockets": "^11",
|
|
25
27
|
"@simplewebauthn/server": "^13.2.2",
|
|
26
28
|
"argon2": "^0.44.0",
|
|
27
29
|
"axios": "^1.9.0",
|
|
@@ -37,16 +39,18 @@
|
|
|
37
39
|
"qrcode": "^1.5.4",
|
|
38
40
|
"redis": "4.7.1",
|
|
39
41
|
"rxjs": "^7.8.2",
|
|
42
|
+
"socket.io": "^4.8.1",
|
|
40
43
|
"sharp": "^0.34.2",
|
|
41
44
|
"speakeasy": "^2.0.0",
|
|
42
45
|
"ua-parser-js": "^2.0.10",
|
|
43
46
|
"uuid": "^11.1.0",
|
|
44
47
|
"@hed-hog/api-prisma": "0.0.6",
|
|
48
|
+
"@hed-hog/api-locale": "0.0.14",
|
|
49
|
+
"@hed-hog/vault-crypto": "0.0.1",
|
|
50
|
+
"@hed-hog/api": "0.0.8",
|
|
45
51
|
"@hed-hog/api-types": "0.0.1",
|
|
46
52
|
"@hed-hog/api-mail": "0.0.9",
|
|
47
|
-
"@hed-hog/api-pagination": "0.0.7"
|
|
48
|
-
"@hed-hog/api-locale": "0.0.14",
|
|
49
|
-
"@hed-hog/api": "0.0.8"
|
|
53
|
+
"@hed-hog/api-pagination": "0.0.7"
|
|
50
54
|
},
|
|
51
55
|
"exports": {
|
|
52
56
|
".": {
|
|
@@ -26,8 +26,10 @@ export class AccessLogInterceptor implements NestInterceptor {
|
|
|
26
26
|
return next.handle().pipe(
|
|
27
27
|
tap(() => {
|
|
28
28
|
const userId: number | undefined = request.auth?.sub;
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// request.ip já resolve o IP real do cliente respeitando `trust proxy` (main.ts):
|
|
30
|
+
// ler x-forwarded-for na mão aqui pegava o primeiro valor da lista, que é
|
|
31
|
+
// exatamente o mais fácil de forjar pelo próprio cliente.
|
|
32
|
+
const ip: string = request.ip ?? '';
|
|
31
33
|
const userAgent: string = (request.headers['user-agent'] as string) ?? '';
|
|
32
34
|
const method: string = request.method ?? '';
|
|
33
35
|
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import {
|
|
3
|
+
attachedFileBlock,
|
|
4
|
+
binaryAttachmentMarker,
|
|
5
|
+
unreadablePdfMarker,
|
|
6
|
+
} from './ai-attachment.fragments';
|
|
7
|
+
import { AiService } from './ai.service';
|
|
8
|
+
|
|
9
|
+
jest.mock('axios');
|
|
10
|
+
|
|
11
|
+
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fidelidade byte a byte da extração.
|
|
15
|
+
*
|
|
16
|
+
* As funções `legacy*` abaixo são cópias literais do que `chatWithGemini` e
|
|
17
|
+
* `buildOpenAiUserContent` montavam inline antes dos marcadores virarem helpers
|
|
18
|
+
* — `[Attached file: …]` estava triplicado, `[Binary attachment: …]` e
|
|
19
|
+
* `[PDF attachment with unreadable text: …]` moram no mesmo bloco. Um `\n`
|
|
20
|
+
* perdido ou um espaço a mais em torno dos `|` muda o que o modelo recebe SEM
|
|
21
|
+
* levantar erro algum. Este é o único check que pega isso — não "arrume" estas
|
|
22
|
+
* cópias.
|
|
23
|
+
*
|
|
24
|
+
* Repare no ponto delicado: no legado do OpenAI o `\n\n` ficava no template do
|
|
25
|
+
* `return`, e agora vem de dentro de `attachedFileBlock`. Os bytes finais são os
|
|
26
|
+
* mesmos, e é exatamente isso que `legacyOpenAiReturn` prova.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type LegacyAttachment = { filename: string; mimeType: string; buffer: Buffer };
|
|
30
|
+
|
|
31
|
+
function legacyGeminiTextPart(attachment: LegacyAttachment, utf8Text: string): string {
|
|
32
|
+
return `\n\n[Attached file: ${attachment.filename}]\n${utf8Text}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function legacyGeminiPdfPart(attachment: LegacyAttachment, pdfText: string): string {
|
|
36
|
+
return `\n\n[Attached file: ${attachment.filename}]\n${pdfText}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function legacyUnreadablePdf(attachment: LegacyAttachment): string {
|
|
40
|
+
return `[PDF attachment with unreadable text: ${attachment.filename}]`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function legacyBinaryMarker(attachment: LegacyAttachment): string {
|
|
44
|
+
return `[Binary attachment: ${attachment.filename} | ${attachment.mimeType} | ${attachment.buffer.length} bytes]`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function legacyOpenAiReturn(
|
|
48
|
+
message: string,
|
|
49
|
+
attachment: LegacyAttachment,
|
|
50
|
+
text: string,
|
|
51
|
+
): string {
|
|
52
|
+
return `${message}\n\n[Attached file: ${attachment.filename}]\n${text}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function makeAttachment(
|
|
56
|
+
filename: string,
|
|
57
|
+
mimeType: string,
|
|
58
|
+
content: string,
|
|
59
|
+
): LegacyAttachment {
|
|
60
|
+
return { filename, mimeType, buffer: Buffer.from(content, 'utf8') };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const TEXT_ATTACHMENT = makeAttachment('notas.txt', 'text/plain', 'linha 1\nlinha 2');
|
|
64
|
+
const PDF_ATTACHMENT = makeAttachment('contrato.pdf', 'application/pdf', '%PDF-1.4');
|
|
65
|
+
const BINARY_ATTACHMENT = makeAttachment('planilha.xlsx', 'application/octet-stream', 'PK');
|
|
66
|
+
|
|
67
|
+
describe('marcadores de anexo — fidelidade', () => {
|
|
68
|
+
it('bloco de arquivo de texto é idêntico ao original do Gemini', () => {
|
|
69
|
+
const utf8Text = TEXT_ATTACHMENT.buffer.toString('utf8');
|
|
70
|
+
|
|
71
|
+
expect(attachedFileBlock(TEXT_ATTACHMENT.filename, utf8Text)).toBe(
|
|
72
|
+
legacyGeminiTextPart(TEXT_ATTACHMENT, utf8Text),
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('bloco de PDF extraído é idêntico ao original do Gemini', () => {
|
|
77
|
+
const pdfText = 'Cláusula 1ª — objeto do contrato.';
|
|
78
|
+
|
|
79
|
+
expect(attachedFileBlock(PDF_ATTACHMENT.filename, pdfText)).toBe(
|
|
80
|
+
legacyGeminiPdfPart(PDF_ATTACHMENT, pdfText),
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('bloco do OpenAI é idêntico ao original mesmo com o \\n\\n vindo do helper', () => {
|
|
85
|
+
const message = 'Resuma o anexo.';
|
|
86
|
+
const text = TEXT_ATTACHMENT.buffer.toString('utf8');
|
|
87
|
+
|
|
88
|
+
expect(`${message}${attachedFileBlock(TEXT_ATTACHMENT.filename, text)}`).toBe(
|
|
89
|
+
legacyOpenAiReturn(message, TEXT_ATTACHMENT, text),
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('marcador de binário é idêntico ao original, com os pipes espaçados', () => {
|
|
94
|
+
expect(
|
|
95
|
+
binaryAttachmentMarker(
|
|
96
|
+
BINARY_ATTACHMENT.filename,
|
|
97
|
+
BINARY_ATTACHMENT.mimeType,
|
|
98
|
+
BINARY_ATTACHMENT.buffer.length,
|
|
99
|
+
),
|
|
100
|
+
).toBe(legacyBinaryMarker(BINARY_ATTACHMENT));
|
|
101
|
+
|
|
102
|
+
expect(binaryAttachmentMarker('a.bin', 'application/octet-stream', 12)).toBe(
|
|
103
|
+
'[Binary attachment: a.bin | application/octet-stream | 12 bytes]',
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('marcador de PDF ilegível é idêntico ao original', () => {
|
|
108
|
+
expect(unreadablePdfMarker(PDF_ATTACHMENT.filename)).toBe(
|
|
109
|
+
legacyUnreadablePdf(PDF_ATTACHMENT),
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('preserva nome de arquivo com espaço, acento e pipe', () => {
|
|
114
|
+
const weird = makeAttachment('nota fiscal | 2ª via.pdf', 'application/pdf', 'x');
|
|
115
|
+
|
|
116
|
+
expect(attachedFileBlock(weird.filename, 'corpo')).toBe(
|
|
117
|
+
legacyGeminiPdfPart(weird, 'corpo'),
|
|
118
|
+
);
|
|
119
|
+
expect(binaryAttachmentMarker(weird.filename, weird.mimeType, weird.buffer.length)).toBe(
|
|
120
|
+
legacyBinaryMarker(weird),
|
|
121
|
+
);
|
|
122
|
+
expect(unreadablePdfMarker(weird.filename)).toBe(legacyUnreadablePdf(weird));
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('corpo vazio mantém a quebra final, e zero bytes continua "0 bytes"', () => {
|
|
126
|
+
const empty = makeAttachment('vazio.txt', 'text/plain', '');
|
|
127
|
+
|
|
128
|
+
expect(attachedFileBlock(empty.filename, '')).toBe(legacyGeminiTextPart(empty, ''));
|
|
129
|
+
expect(attachedFileBlock(empty.filename, '')).toBe('\n\n[Attached file: vazio.txt]\n');
|
|
130
|
+
expect(binaryAttachmentMarker(empty.filename, empty.mimeType, empty.buffer.length)).toBe(
|
|
131
|
+
legacyBinaryMarker(empty),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* O que sai no fio. Este bloco é o que pega "troquei o call site pelo helper
|
|
138
|
+
* errado" — os asserts comparam o corpo da requisição com as cópias legadas.
|
|
139
|
+
*/
|
|
140
|
+
describe('AiService — anexos no fio', () => {
|
|
141
|
+
let service: AiService;
|
|
142
|
+
|
|
143
|
+
const aiProfile = { apiKey: 'sk-test', model: undefined, timeoutMs: undefined };
|
|
144
|
+
|
|
145
|
+
beforeEach(() => {
|
|
146
|
+
const prisma = {} as any;
|
|
147
|
+
const settingService = { getSettingValues: jest.fn().mockResolvedValue({}) } as any;
|
|
148
|
+
const fileService = {} as any;
|
|
149
|
+
const aiExecution = {
|
|
150
|
+
start: jest.fn().mockResolvedValue(1),
|
|
151
|
+
recordStep: jest.fn().mockResolvedValue(undefined),
|
|
152
|
+
finish: jest.fn().mockResolvedValue(undefined),
|
|
153
|
+
} as any;
|
|
154
|
+
const promptResolver = { resolveMany: jest.fn() };
|
|
155
|
+
|
|
156
|
+
service = new AiService(prisma, settingService, fileService, aiExecution, promptResolver as any);
|
|
157
|
+
|
|
158
|
+
jest.spyOn(service as any, 'getAiProfile').mockResolvedValue(aiProfile);
|
|
159
|
+
jest.spyOn(service as any, 'getDefaultProvider').mockResolvedValue('openai');
|
|
160
|
+
|
|
161
|
+
mockedAxios.post.mockResolvedValue({
|
|
162
|
+
data: {
|
|
163
|
+
choices: [{ message: { content: 'ok' } }],
|
|
164
|
+
candidates: [{ content: { parts: [{ text: 'ok' }] } }],
|
|
165
|
+
},
|
|
166
|
+
} as any);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
afterEach(() => {
|
|
170
|
+
jest.restoreAllMocks();
|
|
171
|
+
mockedAxios.post.mockReset();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
function useAttachment(attachment: LegacyAttachment | null) {
|
|
175
|
+
jest.spyOn(service as any, 'resolveAttachment').mockResolvedValue(attachment);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function lastBody(): Record<string, any> {
|
|
179
|
+
return mockedAxios.post.mock.calls.at(-1)?.[1] as Record<string, any>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
describe('Gemini', () => {
|
|
183
|
+
it('embrulha anexo de texto exatamente como o código original', async () => {
|
|
184
|
+
useAttachment(TEXT_ATTACHMENT);
|
|
185
|
+
|
|
186
|
+
await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
|
|
187
|
+
|
|
188
|
+
expect(lastBody().contents[0].parts[1].text).toBe(
|
|
189
|
+
legacyGeminiTextPart(TEXT_ATTACHMENT, TEXT_ATTACHMENT.buffer.toString('utf8')),
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('embrulha PDF com texto extraído exatamente como o código original', async () => {
|
|
194
|
+
const pdfText = 'Cláusula 1ª — objeto do contrato.';
|
|
195
|
+
useAttachment(PDF_ATTACHMENT);
|
|
196
|
+
jest.spyOn(service as any, 'extractPdfText').mockResolvedValue(pdfText);
|
|
197
|
+
|
|
198
|
+
await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
|
|
199
|
+
|
|
200
|
+
expect(lastBody().contents[0].parts[1].text).toBe(
|
|
201
|
+
legacyGeminiPdfPart(PDF_ATTACHMENT, pdfText),
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('PDF ilegível continua indo como inline_data, sem marcador de texto', async () => {
|
|
206
|
+
useAttachment(PDF_ATTACHMENT);
|
|
207
|
+
jest.spyOn(service as any, 'extractPdfText').mockResolvedValue('');
|
|
208
|
+
|
|
209
|
+
await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
|
|
210
|
+
|
|
211
|
+
const part = lastBody().contents[0].parts[1];
|
|
212
|
+
expect(part).not.toHaveProperty('text');
|
|
213
|
+
expect(part.inline_data.mime_type).toBe('application/pdf');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('binário continua indo como inline_data, sem marcador de texto', async () => {
|
|
217
|
+
useAttachment(BINARY_ATTACHMENT);
|
|
218
|
+
|
|
219
|
+
await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
|
|
220
|
+
|
|
221
|
+
const part = lastBody().contents[0].parts[1];
|
|
222
|
+
expect(part).not.toHaveProperty('text');
|
|
223
|
+
expect(part.inline_data.mime_type).toBe('application/octet-stream');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('sem anexo, a mensagem vai crua num único part', async () => {
|
|
227
|
+
useAttachment(null);
|
|
228
|
+
|
|
229
|
+
await service.chat({ message: 'Resuma.', provider: 'gemini' } as any);
|
|
230
|
+
|
|
231
|
+
expect(lastBody().contents[0].parts).toHaveLength(1);
|
|
232
|
+
expect(lastBody().contents[0].parts[0].text).toBe('Resuma.');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('OpenAI', () => {
|
|
237
|
+
it('embrulha anexo de texto exatamente como o código original', async () => {
|
|
238
|
+
useAttachment(TEXT_ATTACHMENT);
|
|
239
|
+
|
|
240
|
+
await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
|
|
241
|
+
|
|
242
|
+
expect(lastBody().messages[0].content).toBe(
|
|
243
|
+
legacyOpenAiReturn(
|
|
244
|
+
'Resuma.',
|
|
245
|
+
TEXT_ATTACHMENT,
|
|
246
|
+
TEXT_ATTACHMENT.buffer.toString('utf8'),
|
|
247
|
+
),
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('embrulha PDF com texto extraído exatamente como o código original', async () => {
|
|
252
|
+
const pdfText = 'Cláusula 1ª — objeto do contrato.';
|
|
253
|
+
useAttachment(PDF_ATTACHMENT);
|
|
254
|
+
jest.spyOn(service as any, 'extractPdfText').mockResolvedValue(pdfText);
|
|
255
|
+
|
|
256
|
+
await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
|
|
257
|
+
|
|
258
|
+
expect(lastBody().messages[0].content).toBe(
|
|
259
|
+
legacyOpenAiReturn('Resuma.', PDF_ATTACHMENT, pdfText),
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('PDF ilegível cai no marcador de PDF, dentro do bloco de arquivo', async () => {
|
|
264
|
+
useAttachment(PDF_ATTACHMENT);
|
|
265
|
+
jest.spyOn(service as any, 'extractPdfText').mockResolvedValue('');
|
|
266
|
+
|
|
267
|
+
await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
|
|
268
|
+
|
|
269
|
+
expect(lastBody().messages[0].content).toBe(
|
|
270
|
+
legacyOpenAiReturn('Resuma.', PDF_ATTACHMENT, legacyUnreadablePdf(PDF_ATTACHMENT)),
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('binário cai no marcador de binário, dentro do bloco de arquivo', async () => {
|
|
275
|
+
useAttachment(BINARY_ATTACHMENT);
|
|
276
|
+
|
|
277
|
+
await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
|
|
278
|
+
|
|
279
|
+
expect(lastBody().messages[0].content).toBe(
|
|
280
|
+
legacyOpenAiReturn(
|
|
281
|
+
'Resuma.',
|
|
282
|
+
BINARY_ATTACHMENT,
|
|
283
|
+
legacyBinaryMarker(BINARY_ATTACHMENT),
|
|
284
|
+
),
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('imagem continua indo por image_url, sem nenhum marcador', async () => {
|
|
289
|
+
const image = makeAttachment('foto.png', 'image/png', 'binario');
|
|
290
|
+
useAttachment(image);
|
|
291
|
+
|
|
292
|
+
await service.chat({ message: 'Descreva.', provider: 'openai' } as any);
|
|
293
|
+
|
|
294
|
+
const content = lastBody().messages[0].content;
|
|
295
|
+
expect(content[0]).toEqual({ type: 'text', text: 'Descreva.' });
|
|
296
|
+
expect(content[1].type).toBe('image_url');
|
|
297
|
+
expect(JSON.stringify(content)).not.toContain('[Attached file:');
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('no DeepSeek, imagem cai no marcador de binário (o modelo não tem visão)', async () => {
|
|
301
|
+
const image = makeAttachment('foto.png', 'image/png', 'binario');
|
|
302
|
+
useAttachment(image);
|
|
303
|
+
|
|
304
|
+
await service.chat({ message: 'Descreva.', provider: 'deepseek' } as any);
|
|
305
|
+
|
|
306
|
+
expect(lastBody().messages[0].content).toBe(
|
|
307
|
+
legacyOpenAiReturn('Descreva.', image, legacyBinaryMarker(image)),
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('sem anexo, a mensagem vai crua — sem \\n\\n pendurado', async () => {
|
|
312
|
+
useAttachment(null);
|
|
313
|
+
|
|
314
|
+
await service.chat({ message: 'Resuma.', provider: 'openai' } as any);
|
|
315
|
+
|
|
316
|
+
expect(lastBody().messages[0].content).toBe('Resuma.');
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framing mecânico de anexo enviado ao modelo — deliberadamente FORA do registry
|
|
3
|
+
* de `ai_instruction` (ver o docblock de `ai.prompts.ts`).
|
|
4
|
+
*
|
|
5
|
+
* Estes marcadores andam em lockstep com `isTextMime`/`isPdfMime`/`extractPdfText`
|
|
6
|
+
* em `ai.service.ts`: são o que diz ao modelo que o texto a seguir é o conteúdo de
|
|
7
|
+
* um arquivo, e não a mensagem do usuário. Antes estavam copiados literalmente nos
|
|
8
|
+
* dois caminhos de provider (Gemini e OpenAI), onde uma cópia podia ser corrigida
|
|
9
|
+
* e a outra esquecida sem gerar erro nenhum.
|
|
10
|
+
*
|
|
11
|
+
* O `\n\n` inicial faz parte do bloco: no Gemini ele abre um `part` separado, no
|
|
12
|
+
* OpenAI ele é a junta logo depois de `${message}`. Nos dois casos os bytes finais
|
|
13
|
+
* são exatamente os mesmos.
|
|
14
|
+
*
|
|
15
|
+
* Coberto byte a byte por `ai-attachment.fragments.spec.ts` — não "arrume" o texto.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Bloco que embrulha o conteúdo textual extraído de um anexo. */
|
|
19
|
+
export function attachedFileBlock(filename: string, body: string): string {
|
|
20
|
+
return `\n\n[Attached file: ${filename}]\n${body}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Usado quando o anexo não é texto nem PDF legível e vai apenas descrito. */
|
|
24
|
+
export function binaryAttachmentMarker(
|
|
25
|
+
filename: string,
|
|
26
|
+
mimeType: string,
|
|
27
|
+
bytes: number,
|
|
28
|
+
): string {
|
|
29
|
+
return `[Binary attachment: ${filename} | ${mimeType} | ${bytes} bytes]`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Usado quando `extractPdfText` não consegue extrair nada do PDF. */
|
|
33
|
+
export function unreadablePdfMarker(filename: string): string {
|
|
34
|
+
return `[PDF attachment with unreadable text: ${filename}]`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { registerAiPrompts } from '../ai-instruction/ai-prompt-registry';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Core AI prompts.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately NOT moved here: the attachment wrappers (`[Attached file: …]`,
|
|
7
|
+
* `[Binary attachment: …]`, `[PDF attachment with unreadable text: …]`). Those are
|
|
8
|
+
* mechanical framing that must stay in lockstep with `isTextMime`/`isPdfMime`/
|
|
9
|
+
* `buildOpenAiUserContent` on the parsing side — editable prose they are not.
|
|
10
|
+
* They now live in `ai-attachment.fragments.ts` (single copy, in code), covered
|
|
11
|
+
* byte for byte by `ai-attachment.fragments.spec.ts`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const CORE_AI_PROMPT_SLUGS = {
|
|
15
|
+
agentDefaultInstructions: 'task.core.ai-agent.default-instructions.system',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
/** Used when an agent is created without explicit instructions. */
|
|
19
|
+
export const AGENT_DEFAULT_INSTRUCTIONS_PROMPT =
|
|
20
|
+
'You are the assistant identified by slug {{slug}}.';
|
|
21
|
+
|
|
22
|
+
registerAiPrompts([
|
|
23
|
+
{
|
|
24
|
+
slug: CORE_AI_PROMPT_SLUGS.agentDefaultInstructions,
|
|
25
|
+
name: 'AI agent — instruções padrão',
|
|
26
|
+
moduleSlug: 'core',
|
|
27
|
+
locale: 'en',
|
|
28
|
+
fallback: AGENT_DEFAULT_INSTRUCTIONS_PROMPT,
|
|
29
|
+
variables: {
|
|
30
|
+
slug: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
required: true,
|
|
33
|
+
description: 'Slug do agente sendo criado.',
|
|
34
|
+
sample: 'finance-payable-extractor',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
]);
|