@hed-hog/core 0.0.355 → 0.0.358
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/dist/ai/ai.service.d.ts +3 -12
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +34 -125
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +6 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +33 -2
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +3 -3
- package/dist/core.module.js.map +1 -1
- package/dist/file/file.controller.d.ts +4 -2
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +44 -38
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +2 -2
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +58 -89
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +10 -15
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +8 -9
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +11 -10
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.enum.d.ts +2 -1
- package/dist/file/provider/provider.enum.d.ts.map +1 -1
- package/dist/file/provider/provider.enum.js +1 -0
- package/dist/file/provider/provider.enum.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +18 -5
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +4 -20
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts +27 -0
- package/dist/file/provider/spaces.provider.d.ts.map +1 -0
- package/dist/file/provider/spaces.provider.js +203 -0
- package/dist/file/provider/spaces.provider.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/dto/create.dto.d.ts +9 -0
- package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/create.dto.js +54 -0
- package/dist/integration-profile/dto/create.dto.js.map +1 -0
- package/dist/integration-profile/dto/export.dto.d.ts +5 -0
- package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/export.dto.js +29 -0
- package/dist/integration-profile/dto/export.dto.js.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
- package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
- package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
- package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
- package/dist/integration-profile/dto/update.dto.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.controller.js +166 -0
- package/dist/integration-profile/integration-profile.controller.js.map +1 -0
- package/dist/integration-profile/integration-profile.module.d.ts +3 -0
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
- package/dist/{mail-profile/mail-profile.module.js → integration-profile/integration-profile.module.js} +11 -13
- package/dist/integration-profile/integration-profile.module.js.map +1 -0
- package/dist/integration-profile/integration-profile.service.d.ts +160 -0
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.service.js +609 -0
- package/dist/integration-profile/integration-profile.service.js.map +1 -0
- package/dist/integration-profile/integration-profile.utils.d.ts +30 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.utils.js +156 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -0
- package/dist/mail/mail.module.d.ts.map +1 -1
- package/dist/mail/mail.module.js +36 -23
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +4 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +33 -51
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.controller.js +1 -1
- package/dist/mcp/mcp-api-key.controller.js.map +1 -1
- package/dist/mcp/mcp-api-key.service.d.ts +2 -1
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
- package/dist/mcp/mcp-api-key.service.js +6 -2
- package/dist/mcp/mcp-api-key.service.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +3 -5
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +17 -16
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
- package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -1
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +31 -5
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +12 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +125 -23
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.d.ts +5 -2
- package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
- package/dist/oauth/providers/facebook.provider.js +34 -19
- package/dist/oauth/providers/facebook.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +6 -2
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +43 -20
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/google.provider.d.ts +5 -2
- package/dist/oauth/providers/google.provider.d.ts.map +1 -1
- package/dist/oauth/providers/google.provider.js +34 -19
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
- package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft.provider.js +34 -19
- package/dist/oauth/providers/microsoft.provider.js.map +1 -1
- package/dist/profile/profile.controller.js +1 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/security/security.service.d.ts +2 -0
- package/dist/security/security.service.d.ts.map +1 -1
- package/dist/security/security.service.js +21 -0
- package/dist/security/security.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +26 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +240 -7
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -1
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +5 -4
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +4 -2
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +19 -4
- package/dist/user/user.service.js.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
- package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
- package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.controller.js +10 -0
- package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
- package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
- package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
- package/dist/webhook-integration/event-webhook.service.js +30 -0
- package/dist/webhook-integration/event-webhook.service.js.map +1 -1
- package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
- package/dist/webhook-integration/webhook-command.registry.js +36 -0
- package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +20 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +48 -0
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.js +5 -0
- package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +27 -2
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +377 -50
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/file_provider.yaml +9 -1
- package/hedhog/data/integration_provider.yaml +148 -0
- package/hedhog/data/integration_type.yaml +29 -0
- package/hedhog/data/menu.yaml +6 -21
- package/hedhog/data/role.yaml +8 -0
- package/hedhog/data/route.yaml +73 -373
- package/hedhog/data/setting_group.yaml +209 -365
- package/hedhog/data/setting_subgroup.yaml +21 -13
- package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +938 -225
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1830 -0
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +829 -128
- package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +1 -820
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
- package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
- package/hedhog/frontend/messages/en.json +239 -3
- package/hedhog/frontend/messages/pt.json +239 -3
- package/hedhog/table/file.yaml +1 -1
- package/hedhog/table/integration_profile.yaml +34 -0
- package/hedhog/table/integration_provider.yaml +23 -0
- package/hedhog/table/integration_type.yaml +19 -0
- package/hedhog/table/mcp_api_key.yaml +4 -0
- package/hedhog/table/webhook_action.yaml +141 -85
- package/package.json +4 -3
- package/src/ai/ai.service.ts +35 -153
- package/src/auth/guards/auth.guard.ts +32 -0
- package/src/core.module.ts +3 -3
- package/src/file/file.controller.ts +51 -42
- package/src/file/file.service.ts +67 -104
- package/src/file/provider/azure.provider.ts +14 -28
- package/src/file/provider/gcs.provider.ts +9 -9
- package/src/file/provider/local.provider.ts +10 -13
- package/src/file/provider/provider.enum.ts +1 -0
- package/src/file/provider/provider.factory.ts +21 -6
- package/src/file/provider/s3.provider.ts +4 -20
- package/src/file/provider/spaces.provider.ts +246 -0
- package/src/index.ts +6 -3
- package/src/integration-profile/dto/create.dto.ts +44 -0
- package/src/integration-profile/dto/export.dto.ts +15 -0
- package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
- package/src/integration-profile/integration-profile.controller.ts +131 -0
- package/src/integration-profile/integration-profile.module.ts +16 -0
- package/src/integration-profile/integration-profile.service.ts +793 -0
- package/src/integration-profile/integration-profile.utils.ts +173 -0
- package/src/mail/mail.module.ts +41 -22
- package/src/mail/mail.service.ts +40 -64
- package/src/mcp/guards/mcp-auth.guard.ts +1 -1
- package/src/mcp/mcp-api-key.controller.ts +2 -2
- package/src/mcp/mcp-api-key.service.ts +6 -2
- package/src/mcp/mcp.module.ts +3 -5
- package/src/mcp-chat/mcp-chat.service.ts +23 -20
- package/src/oauth/interfaces/OAuthProvider.ts +1 -1
- package/src/oauth/oauth.controller.ts +30 -2
- package/src/oauth/oauth.service.ts +194 -35
- package/src/oauth/providers/abstract.provider.ts +1 -1
- package/src/oauth/providers/facebook.provider.ts +36 -20
- package/src/oauth/providers/github.provider.ts +46 -23
- package/src/oauth/providers/google.provider.ts +36 -20
- package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
- package/src/oauth/providers/microsoft.provider.ts +36 -21
- package/src/profile/profile.controller.ts +2 -2
- package/src/security/security.service.ts +34 -1
- package/src/setting/setting.service.ts +307 -9
- package/src/user/user.controller.ts +4 -1
- package/src/user/user.service.ts +20 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
- package/src/webhook-integration/event-webhook.controller.ts +55 -50
- package/src/webhook-integration/event-webhook.service.ts +422 -384
- package/src/webhook-integration/webhook-command.registry.ts +42 -0
- package/src/webhook-integration/webhook-integration.controller.ts +25 -0
- package/src/webhook-integration/webhook-integration.module.ts +50 -45
- package/src/webhook-integration/webhook-integration.service.ts +444 -53
- package/dist/mail-profile/dto/create.dto.d.ts +0 -23
- package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/create.dto.js +0 -139
- package/dist/mail-profile/dto/create.dto.js.map +0 -1
- package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
- package/dist/mail-profile/dto/update.dto.js.map +0 -1
- package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
- package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.controller.js +0 -95
- package/dist/mail-profile/mail-profile.controller.js.map +0 -1
- package/dist/mail-profile/mail-profile.module.d.ts +0 -3
- package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.module.js.map +0 -1
- package/dist/mail-profile/mail-profile.service.d.ts +0 -109
- package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
- package/dist/mail-profile/mail-profile.service.js +0 -278
- package/dist/mail-profile/mail-profile.service.js.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -32
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -178
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
- package/hedhog/data/mail_profile.yaml +0 -18
- package/hedhog/table/mail_profile.yaml +0 -75
- package/src/mail-profile/dto/create.dto.ts +0 -145
- package/src/mail-profile/mail-profile.controller.ts +0 -56
- package/src/mail-profile/mail-profile.module.ts +0 -18
- package/src/mail-profile/mail-profile.service.ts +0 -308
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -128
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.d.ts +0 -0
- /package/dist/{mail-profile → integration-profile}/dto/update.dto.js +0 -0
- /package/src/{mail-profile → integration-profile}/dto/update.dto.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.358",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -27,16 +27,17 @@
|
|
|
27
27
|
"playwright": "^1.49.0",
|
|
28
28
|
"png-to-ico": "^2.1.8",
|
|
29
29
|
"qrcode": "^1.5.4",
|
|
30
|
+
"redis": "4.7.1",
|
|
30
31
|
"rxjs": "^7.8.2",
|
|
31
32
|
"sharp": "^0.34.2",
|
|
32
33
|
"speakeasy": "^2.0.0",
|
|
33
34
|
"uuid": "^11.1.0",
|
|
34
35
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
35
36
|
"@hed-hog/api-locale": "0.0.14",
|
|
37
|
+
"@hed-hog/api-mail": "0.0.9",
|
|
36
38
|
"@hed-hog/api": "0.0.8",
|
|
37
|
-
"@hed-hog/api-pagination": "0.0.7",
|
|
38
39
|
"@hed-hog/api-prisma": "0.0.6",
|
|
39
|
-
"@hed-hog/api-
|
|
40
|
+
"@hed-hog/api-pagination": "0.0.7",
|
|
40
41
|
"@hed-hog/api-types": "0.0.1"
|
|
41
42
|
},
|
|
42
43
|
"exports": {
|
package/src/ai/ai.service.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { createHash } from 'crypto';
|
|
|
14
14
|
import pdfParse from 'pdf-parse';
|
|
15
15
|
import { DeleteDTO } from '../dto/delete.dto';
|
|
16
16
|
import { FileService } from '../file/file.service';
|
|
17
|
-
import {
|
|
17
|
+
import { buildAiConfigFromIntegration } from '../integration-profile/integration-profile.utils';
|
|
18
18
|
import { SettingService } from '../setting/setting.service';
|
|
19
19
|
import { ChatAgentDTO } from './dto/chat-agent.dto';
|
|
20
20
|
import { ChatDTO } from './dto/chat.dto';
|
|
@@ -40,8 +40,6 @@ type AiAttachment = {
|
|
|
40
40
|
buffer: Buffer;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
type AiProviderKeySettingSlug = 'ai-openai-api-key' | 'ai-gemini-api-key';
|
|
44
|
-
|
|
45
43
|
@Injectable()
|
|
46
44
|
export class AiService implements OnModuleInit {
|
|
47
45
|
private readonly logger = new Logger(AiService.name);
|
|
@@ -53,27 +51,18 @@ export class AiService implements OnModuleInit {
|
|
|
53
51
|
private readonly settingService: SettingService,
|
|
54
52
|
@Inject(forwardRef(() => FileService))
|
|
55
53
|
private readonly fileService: FileService,
|
|
56
|
-
@Inject(forwardRef(() => IntegrationDeveloperApiService))
|
|
57
|
-
private readonly integrationApi: IntegrationDeveloperApiService,
|
|
58
54
|
) {}
|
|
59
55
|
|
|
60
|
-
onModuleInit()
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
await this.syncProviderEnabledFlag(slug);
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
void this.syncAllProviderEnabledFlags();
|
|
56
|
+
async onModuleInit() {
|
|
57
|
+
try {
|
|
58
|
+
const s = await this.settingService.getSettingValues([
|
|
59
|
+
'ai-openai-profile-id',
|
|
60
|
+
'ai-gemini-profile-id',
|
|
61
|
+
]);
|
|
62
|
+
if (!Number(s['ai-openai-profile-id']) && !Number(s['ai-gemini-profile-id'])) {
|
|
63
|
+
this.logger.warn('No AI profiles configured. Set profiles in Settings → AI.');
|
|
64
|
+
}
|
|
65
|
+
} catch { /* settings not available yet */ }
|
|
77
66
|
}
|
|
78
67
|
|
|
79
68
|
async chat(data: ChatDTO, file?: MulterFile) {
|
|
@@ -423,119 +412,36 @@ export class AiService implements OnModuleInit {
|
|
|
423
412
|
return 'gemini-1.5-flash';
|
|
424
413
|
}
|
|
425
414
|
|
|
426
|
-
private
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
private getEnabledSlugFromProviderKey(slug: AiProviderKeySettingSlug) {
|
|
431
|
-
return slug === 'ai-openai-api-key'
|
|
432
|
-
? 'ai-openai-api-key-enabled'
|
|
433
|
-
: 'ai-gemini-api-key-enabled';
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
private async syncAllProviderEnabledFlags() {
|
|
437
|
-
const results = await Promise.allSettled([
|
|
438
|
-
this.syncProviderEnabledFlag('ai-openai-api-key'),
|
|
439
|
-
this.syncProviderEnabledFlag('ai-gemini-api-key'),
|
|
440
|
-
]);
|
|
441
|
-
|
|
442
|
-
results.forEach((result, index) => {
|
|
443
|
-
if (result.status === 'rejected') {
|
|
444
|
-
const slug = index === 0 ? 'ai-openai-api-key' : 'ai-gemini-api-key';
|
|
445
|
-
this.logger.warn(
|
|
446
|
-
`Failed to sync provider availability for ${slug}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`,
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
private async syncProviderEnabledFlag(slug: AiProviderKeySettingSlug) {
|
|
453
|
-
const values = await this.settingService.getSettingValues(slug);
|
|
454
|
-
const apiKey = String(values?.[slug] || '').trim();
|
|
455
|
-
const enabledSlug = this.getEnabledSlugFromProviderKey(slug);
|
|
456
|
-
|
|
457
|
-
const isValid = slug === 'ai-openai-api-key'
|
|
458
|
-
? await this.validateOpenAiKey(apiKey)
|
|
459
|
-
: await this.validateGeminiKey(apiKey);
|
|
460
|
-
|
|
461
|
-
await this.settingService.setValue(enabledSlug, isValid ? 'true' : 'false');
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
private getValidationErrorMessage(error: unknown) {
|
|
465
|
-
if (axios.isAxiosError(error)) {
|
|
466
|
-
const providerMessage =
|
|
467
|
-
error.response?.data?.error?.message ||
|
|
468
|
-
error.response?.data?.message ||
|
|
469
|
-
error.message;
|
|
470
|
-
const status = error.response?.status || 'network';
|
|
471
|
-
return `${status}: ${providerMessage}`;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return error instanceof Error ? error.message : String(error);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
private async validateOpenAiKey(apiKey?: string | null): Promise<boolean> {
|
|
478
|
-
const normalizedKey = String(apiKey || '').trim();
|
|
479
|
-
|
|
480
|
-
if (!normalizedKey) {
|
|
481
|
-
return false;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
try {
|
|
485
|
-
await axios.get('https://api.openai.com/v1/models', {
|
|
486
|
-
headers: {
|
|
487
|
-
Authorization: `Bearer ${normalizedKey}`,
|
|
488
|
-
},
|
|
489
|
-
params: {
|
|
490
|
-
limit: 1,
|
|
491
|
-
},
|
|
492
|
-
timeout: 5000,
|
|
493
|
-
});
|
|
415
|
+
private async getAiApiKey(provider: AiProvider): Promise<string> {
|
|
416
|
+
const slug = provider === 'openai' ? 'ai-openai-profile-id' : 'ai-gemini-profile-id';
|
|
417
|
+
const settings = await this.settingService.getSettingValues([slug]);
|
|
418
|
+
const profileId = Number(settings[slug]);
|
|
494
419
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
`OpenAI key validation failed: ${this.getValidationErrorMessage(error)}`,
|
|
420
|
+
if (!profileId) {
|
|
421
|
+
throw new BadRequestException(
|
|
422
|
+
`No ${provider} AI profile configured. Set one in Settings → AI.`,
|
|
499
423
|
);
|
|
500
|
-
return false;
|
|
501
424
|
}
|
|
502
|
-
}
|
|
503
425
|
|
|
504
|
-
|
|
505
|
-
|
|
426
|
+
const profile = await this.prismaService.integration_profile.findUnique({
|
|
427
|
+
where: { id: profileId },
|
|
428
|
+
include: { integration_provider: { select: { slug: true } } },
|
|
429
|
+
});
|
|
506
430
|
|
|
507
|
-
if (!
|
|
508
|
-
|
|
431
|
+
if (!profile) {
|
|
432
|
+
throw new BadRequestException(`AI profile ${profileId} not found.`);
|
|
509
433
|
}
|
|
510
434
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
pageSize: 1,
|
|
516
|
-
},
|
|
517
|
-
timeout: 5000,
|
|
518
|
-
});
|
|
435
|
+
const { apiKey } = buildAiConfigFromIntegration(
|
|
436
|
+
profile.integration_provider.slug,
|
|
437
|
+
profile.config,
|
|
438
|
+
);
|
|
519
439
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.logger.warn(
|
|
523
|
-
`Gemini key validation failed: ${this.getValidationErrorMessage(error)}`,
|
|
524
|
-
);
|
|
525
|
-
return false;
|
|
440
|
+
if (!apiKey) {
|
|
441
|
+
throw new BadRequestException(`AI profile ${profileId} has no API key configured.`);
|
|
526
442
|
}
|
|
527
|
-
}
|
|
528
443
|
|
|
529
|
-
|
|
530
|
-
const settings = await this.settingService.getSettingValues([
|
|
531
|
-
'ai-openai-api-key',
|
|
532
|
-
'ai-gemini-api-key',
|
|
533
|
-
]);
|
|
534
|
-
|
|
535
|
-
return {
|
|
536
|
-
openai: settings['ai-openai-api-key'],
|
|
537
|
-
gemini: settings['ai-gemini-api-key'],
|
|
538
|
-
};
|
|
444
|
+
return apiKey;
|
|
539
445
|
}
|
|
540
446
|
|
|
541
447
|
private async chatWithOpenAi({
|
|
@@ -549,13 +455,7 @@ export class AiService implements OnModuleInit {
|
|
|
549
455
|
systemPrompt?: string;
|
|
550
456
|
attachment?: AiAttachment | null;
|
|
551
457
|
}) {
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
if (!openai) {
|
|
555
|
-
throw new BadRequestException(
|
|
556
|
-
'OpenAI API key is not configured (setting "ai-openai-api-key").',
|
|
557
|
-
);
|
|
558
|
-
}
|
|
458
|
+
const openai = await this.getAiApiKey('openai');
|
|
559
459
|
|
|
560
460
|
const messages: Array<any> = [];
|
|
561
461
|
|
|
@@ -592,13 +492,7 @@ export class AiService implements OnModuleInit {
|
|
|
592
492
|
model: string;
|
|
593
493
|
instructions: string | null;
|
|
594
494
|
}): Promise<string> {
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
if (!openai) {
|
|
598
|
-
throw new BadRequestException(
|
|
599
|
-
'OpenAI API key is not configured (setting "ai-openai-api-key").',
|
|
600
|
-
);
|
|
601
|
-
}
|
|
495
|
+
const openai = await this.getAiApiKey('openai');
|
|
602
496
|
|
|
603
497
|
const response = await axios.post(
|
|
604
498
|
'https://api.openai.com/v1/assistants',
|
|
@@ -629,13 +523,7 @@ export class AiService implements OnModuleInit {
|
|
|
629
523
|
assistantId: string,
|
|
630
524
|
message: string,
|
|
631
525
|
): Promise<string> {
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
if (!openai) {
|
|
635
|
-
throw new BadRequestException(
|
|
636
|
-
'OpenAI API key is not configured (setting "ai-openai-api-key").',
|
|
637
|
-
);
|
|
638
|
-
}
|
|
526
|
+
const openai = await this.getAiApiKey('openai');
|
|
639
527
|
|
|
640
528
|
const threadResponse = await axios.post(
|
|
641
529
|
'https://api.openai.com/v1/threads',
|
|
@@ -733,13 +621,7 @@ export class AiService implements OnModuleInit {
|
|
|
733
621
|
systemPrompt?: string;
|
|
734
622
|
attachment?: AiAttachment | null;
|
|
735
623
|
}) {
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
if (!gemini) {
|
|
739
|
-
throw new BadRequestException(
|
|
740
|
-
'Gemini API key is not configured (setting "ai-gemini-api-key").',
|
|
741
|
-
);
|
|
742
|
-
}
|
|
624
|
+
const gemini = await this.getAiApiKey('gemini');
|
|
743
625
|
|
|
744
626
|
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${gemini}`;
|
|
745
627
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IS_PUBLIC_KEY, WITH_NO_ROLE, WITH_ROLE } from '@hed-hog/api';
|
|
2
2
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
3
|
+
import { PrismaService } from '@hed-hog/api-prisma';
|
|
3
4
|
import {
|
|
4
5
|
CanActivate,
|
|
5
6
|
ExecutionContext,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
} from '@nestjs/common';
|
|
9
10
|
import { Reflector } from '@nestjs/core';
|
|
10
11
|
import { Request } from 'express';
|
|
12
|
+
import { SecurityService } from '../../security/security.service';
|
|
11
13
|
import { TokenService } from '../../token/token.service';
|
|
12
14
|
|
|
13
15
|
@Injectable()
|
|
@@ -15,6 +17,8 @@ export class AuthGuard implements CanActivate {
|
|
|
15
17
|
constructor(
|
|
16
18
|
private token: TokenService,
|
|
17
19
|
private reflector: Reflector,
|
|
20
|
+
private prisma: PrismaService,
|
|
21
|
+
private security: SecurityService,
|
|
18
22
|
) { }
|
|
19
23
|
|
|
20
24
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
@@ -37,6 +41,10 @@ export class AuthGuard implements CanActivate {
|
|
|
37
41
|
const token = this.extractTokenFromHeader(request);
|
|
38
42
|
const locale = request.headers['locale'] || request.headers['accept-language'] || 'en';
|
|
39
43
|
|
|
44
|
+
if (token?.startsWith('hedhog_api_')) {
|
|
45
|
+
return this.verifyApiKey(request, token, isPublic);
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
// If endpoint requires role/authentication and no token provided
|
|
41
49
|
if (!token) {
|
|
42
50
|
if (isPublic) {
|
|
@@ -76,6 +84,30 @@ export class AuthGuard implements CanActivate {
|
|
|
76
84
|
return true;
|
|
77
85
|
}
|
|
78
86
|
|
|
87
|
+
private async verifyApiKey(request: Request, token: string, isPublic: boolean): Promise<boolean> {
|
|
88
|
+
const hash = this.security.hashWithPepper(token);
|
|
89
|
+
const apiKey = await this.prisma.mcp_api_key.findFirst({
|
|
90
|
+
where: { token_hash: hash, type: 'api', revoked_at: null },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (!apiKey) {
|
|
94
|
+
if (isPublic) return true;
|
|
95
|
+
throw new UnauthorizedException('Invalid API key');
|
|
96
|
+
}
|
|
97
|
+
if (apiKey.expires_at && apiKey.expires_at <= new Date()) {
|
|
98
|
+
if (isPublic) return true;
|
|
99
|
+
throw new UnauthorizedException('API key expired');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.prisma.mcp_api_key.update({
|
|
103
|
+
where: { id: apiKey.id },
|
|
104
|
+
data: { last_used_at: new Date() },
|
|
105
|
+
}).catch(() => {});
|
|
106
|
+
|
|
107
|
+
request['auth'] = { sub: apiKey.user_id, sessionId: null };
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
|
|
79
111
|
private extractTokenFromHeader(request: Request): string | undefined {
|
|
80
112
|
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
|
81
113
|
|
package/src/core.module.ts
CHANGED
|
@@ -18,7 +18,6 @@ import { FileModule } from './file/file.module';
|
|
|
18
18
|
import { InstallModule } from './install/install.module';
|
|
19
19
|
import { IntegrationModule } from './integration/integration.module';
|
|
20
20
|
import { LocaleModule as CoreLocaleModule } from './locale/locale.module';
|
|
21
|
-
import { MailProfileModule } from './mail-profile/mail-profile.module';
|
|
22
21
|
import { MailSentModule } from './mail-sent/mail-sent.module';
|
|
23
22
|
import { MailModule } from './mail/mail.module';
|
|
24
23
|
import { McpChatModule } from './mcp-chat/mcp-chat.module';
|
|
@@ -42,6 +41,7 @@ import { IsEmailWithSettingsConstraint } from './validators/is-email-with-settin
|
|
|
42
41
|
import { IsPinCodeWithSettingConstraint } from './validators/is-pin-code-with-setting.validator';
|
|
43
42
|
import { IsStrongPasswordWithSettingsConstraint } from './validators/is-strong-password-with-settings.validator';
|
|
44
43
|
import { ValidatorServiceLocator } from './validators/service-locator';
|
|
44
|
+
import { IntegrationProfileModule } from './integration-profile/integration-profile.module';
|
|
45
45
|
import { WebhookIntegrationModule } from './webhook-integration/webhook-integration.module';
|
|
46
46
|
|
|
47
47
|
@Global()
|
|
@@ -66,7 +66,7 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
66
66
|
forwardRef(() => SystemModule),
|
|
67
67
|
forwardRef(() => SettingModule),
|
|
68
68
|
forwardRef(() => MailModule),
|
|
69
|
-
forwardRef(() =>
|
|
69
|
+
forwardRef(() => IntegrationProfileModule),
|
|
70
70
|
forwardRef(() => MailSentModule),
|
|
71
71
|
forwardRef(() => FileModule),
|
|
72
72
|
forwardRef(() => TaskModule),
|
|
@@ -86,7 +86,7 @@ import { WebhookIntegrationModule } from './webhook-integration/webhook-integrat
|
|
|
86
86
|
UserModule,
|
|
87
87
|
AuthModule,
|
|
88
88
|
MailModule,
|
|
89
|
-
|
|
89
|
+
IntegrationProfileModule,
|
|
90
90
|
RouteModule,
|
|
91
91
|
RoleModule,
|
|
92
92
|
MenuModule,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
forwardRef,
|
|
9
9
|
Get,
|
|
10
10
|
Inject,
|
|
11
|
+
Logger,
|
|
11
12
|
Param,
|
|
12
13
|
ParseIntPipe,
|
|
13
14
|
Post,
|
|
@@ -29,11 +30,50 @@ import { FileService } from './file.service';
|
|
|
29
30
|
@Role()
|
|
30
31
|
@Controller('file')
|
|
31
32
|
export class FileController {
|
|
33
|
+
private readonly logger = new Logger(FileController.name);
|
|
34
|
+
|
|
32
35
|
constructor(
|
|
33
36
|
@Inject(forwardRef(() => FileService))
|
|
34
37
|
private readonly fileService: FileService,
|
|
35
38
|
) {}
|
|
36
39
|
|
|
40
|
+
private renderDownloadErrorHtml(locale: string, error: any): string {
|
|
41
|
+
const errorTitle = getLocaleText('file.download.error_title', locale);
|
|
42
|
+
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
43
|
+
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
44
|
+
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
45
|
+
|
|
46
|
+
const templateData = {
|
|
47
|
+
locale: locale || 'en',
|
|
48
|
+
errorTitle,
|
|
49
|
+
errorMessage,
|
|
50
|
+
errorDetailsLabel,
|
|
51
|
+
errorDetails: error?.message || 'Unknown error occurred',
|
|
52
|
+
goBackText,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
57
|
+
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
58
|
+
const template = Handlebars.compile(templateSource);
|
|
59
|
+
return template(templateData);
|
|
60
|
+
} catch (templateError) {
|
|
61
|
+
this.logger.warn(
|
|
62
|
+
`Download error template missing or unreadable: ${templateError instanceof Error ? templateError.message : String(templateError)}`,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const safe = {
|
|
66
|
+
errorTitle: Handlebars.escapeExpression(String(errorTitle)),
|
|
67
|
+
errorMessage: Handlebars.escapeExpression(String(errorMessage)),
|
|
68
|
+
errorDetailsLabel: Handlebars.escapeExpression(String(errorDetailsLabel)),
|
|
69
|
+
errorDetails: Handlebars.escapeExpression(String(templateData.errorDetails)),
|
|
70
|
+
goBackText: Handlebars.escapeExpression(String(goBackText)),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return `<!doctype html><html lang="${Handlebars.escapeExpression(locale || 'en')}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${safe.errorTitle}</title></head><body><h1>${safe.errorTitle}</h1><p>${safe.errorMessage}</p><p><strong>${safe.errorDetailsLabel}</strong> ${safe.errorDetails}</p><button type="button" onclick="history.back()">${safe.goBackText}</button></body></html>`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
37
77
|
@Get()
|
|
38
78
|
async list(@Pagination() paginationParams) {
|
|
39
79
|
return this.fileService.getFiles(paginationParams);
|
|
@@ -45,11 +85,16 @@ export class FileController {
|
|
|
45
85
|
}
|
|
46
86
|
|
|
47
87
|
@Put('open/:id')
|
|
48
|
-
async getTempOpenURL(
|
|
88
|
+
async getTempOpenURL(
|
|
89
|
+
@Param('id', ParseIntPipe) id: number,
|
|
90
|
+
@Req() req: Request,
|
|
91
|
+
) {
|
|
92
|
+
const file = await this.fileService.get(id);
|
|
93
|
+
const token = this.fileService.createDownloadToken(file.path, 3600);
|
|
94
|
+
const origin = `${req.protocol}://${req.get('host')}`;
|
|
95
|
+
|
|
49
96
|
return {
|
|
50
|
-
url:
|
|
51
|
-
(await this.fileService.get(id)).path,
|
|
52
|
-
),
|
|
97
|
+
url: `${origin}/file/open/${encodeURIComponent(token)}`,
|
|
53
98
|
};
|
|
54
99
|
}
|
|
55
100
|
|
|
@@ -96,27 +141,7 @@ export class FileController {
|
|
|
96
141
|
return;
|
|
97
142
|
|
|
98
143
|
} catch (error:any) {
|
|
99
|
-
|
|
100
|
-
const errorTitle = getLocaleText('file.download.error_title', locale);
|
|
101
|
-
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
102
|
-
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
103
|
-
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
104
|
-
|
|
105
|
-
// Ler e compilar template
|
|
106
|
-
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
107
|
-
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
108
|
-
const template = Handlebars.compile(templateSource);
|
|
109
|
-
|
|
110
|
-
// Renderizar template com dados
|
|
111
|
-
const html = template({
|
|
112
|
-
locale: locale || 'en',
|
|
113
|
-
errorTitle,
|
|
114
|
-
errorMessage,
|
|
115
|
-
errorDetailsLabel,
|
|
116
|
-
errorDetails: error?.message || 'Unknown error occurred',
|
|
117
|
-
goBackText,
|
|
118
|
-
});
|
|
119
|
-
|
|
144
|
+
const html = this.renderDownloadErrorHtml(locale, error);
|
|
120
145
|
res.status(400).set('Content-Type', 'text/html').send(html);
|
|
121
146
|
return;
|
|
122
147
|
}
|
|
@@ -176,23 +201,7 @@ export class FileController {
|
|
|
176
201
|
return;
|
|
177
202
|
|
|
178
203
|
} catch (error:any) {
|
|
179
|
-
const
|
|
180
|
-
const errorMessage = getLocaleText('file.download.error_message', locale);
|
|
181
|
-
const errorDetailsLabel = getLocaleText('file.download.error_details', locale);
|
|
182
|
-
const goBackText = getLocaleText('file.download.go_back', locale);
|
|
183
|
-
|
|
184
|
-
const templatePath = join(__dirname, 'templates', 'download-error.html');
|
|
185
|
-
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
186
|
-
const template = Handlebars.compile(templateSource);
|
|
187
|
-
|
|
188
|
-
const html = template({
|
|
189
|
-
locale: locale || 'en',
|
|
190
|
-
errorTitle,
|
|
191
|
-
errorMessage,
|
|
192
|
-
errorDetailsLabel,
|
|
193
|
-
errorDetails: error?.message || 'Unknown error occurred',
|
|
194
|
-
goBackText,
|
|
195
|
-
});
|
|
204
|
+
const html = this.renderDownloadErrorHtml(locale, error);
|
|
196
205
|
|
|
197
206
|
res.status(400).set('Content-Type', 'text/html').send(html);
|
|
198
207
|
return;
|