@hed-hog/core 0.0.354 → 0.0.356

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.
Files changed (167) hide show
  1. package/dist/ai/ai.service.d.ts +3 -12
  2. package/dist/ai/ai.service.d.ts.map +1 -1
  3. package/dist/ai/ai.service.js +34 -125
  4. package/dist/ai/ai.service.js.map +1 -1
  5. package/dist/core.module.d.ts.map +1 -1
  6. package/dist/core.module.js +3 -3
  7. package/dist/core.module.js.map +1 -1
  8. package/dist/file/file.service.d.ts +1 -1
  9. package/dist/file/file.service.d.ts.map +1 -1
  10. package/dist/file/file.service.js +50 -64
  11. package/dist/file/file.service.js.map +1 -1
  12. package/dist/file/provider/provider.enum.d.ts +2 -1
  13. package/dist/file/provider/provider.enum.d.ts.map +1 -1
  14. package/dist/file/provider/provider.enum.js +1 -0
  15. package/dist/file/provider/provider.enum.js.map +1 -1
  16. package/dist/file/provider/provider.factory.d.ts.map +1 -1
  17. package/dist/file/provider/provider.factory.js +3 -0
  18. package/dist/file/provider/provider.factory.js.map +1 -1
  19. package/dist/file/provider/spaces.provider.d.ts +27 -0
  20. package/dist/file/provider/spaces.provider.d.ts.map +1 -0
  21. package/dist/file/provider/spaces.provider.js +218 -0
  22. package/dist/file/provider/spaces.provider.js.map +1 -0
  23. package/dist/index.d.ts +4 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +4 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/integration-profile/dto/create.dto.d.ts +9 -0
  28. package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
  29. package/dist/integration-profile/dto/create.dto.js +54 -0
  30. package/dist/integration-profile/dto/create.dto.js.map +1 -0
  31. package/dist/integration-profile/dto/export.dto.d.ts +5 -0
  32. package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
  33. package/dist/integration-profile/dto/export.dto.js +29 -0
  34. package/dist/integration-profile/dto/export.dto.js.map +1 -0
  35. package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
  36. package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
  37. package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
  38. package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
  39. package/dist/integration-profile/dto/update.dto.d.ts +6 -0
  40. package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
  41. package/dist/integration-profile/dto/update.dto.js +9 -0
  42. package/dist/integration-profile/dto/update.dto.js.map +1 -0
  43. package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
  44. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
  45. package/dist/integration-profile/integration-profile.controller.js +165 -0
  46. package/dist/integration-profile/integration-profile.controller.js.map +1 -0
  47. package/dist/integration-profile/integration-profile.module.d.ts +3 -0
  48. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
  49. package/dist/integration-profile/integration-profile.module.js +29 -0
  50. package/dist/integration-profile/integration-profile.module.js.map +1 -0
  51. package/dist/integration-profile/integration-profile.service.d.ts +160 -0
  52. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
  53. package/dist/integration-profile/integration-profile.service.js +606 -0
  54. package/dist/integration-profile/integration-profile.service.js.map +1 -0
  55. package/dist/integration-profile/integration-profile.utils.d.ts +24 -0
  56. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
  57. package/dist/integration-profile/integration-profile.utils.js +147 -0
  58. package/dist/integration-profile/integration-profile.utils.js.map +1 -0
  59. package/dist/mail/mail.module.d.ts.map +1 -1
  60. package/dist/mail/mail.module.js +27 -19
  61. package/dist/mail/mail.module.js.map +1 -1
  62. package/dist/mail/mail.service.d.ts +3 -2
  63. package/dist/mail/mail.service.d.ts.map +1 -1
  64. package/dist/mail/mail.service.js +25 -47
  65. package/dist/mail/mail.service.js.map +1 -1
  66. package/dist/mcp/mcp.module.js +2 -2
  67. package/dist/mcp/mcp.module.js.map +1 -1
  68. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +3 -15
  69. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -1
  70. package/dist/mcp/tools/core-mail-profile.mcp-tools.js +12 -94
  71. package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -1
  72. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  73. package/dist/mcp-chat/mcp-chat.service.js +17 -16
  74. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  75. package/dist/setting/setting.service.d.ts.map +1 -1
  76. package/dist/setting/setting.service.js +0 -2
  77. package/dist/setting/setting.service.js.map +1 -1
  78. package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
  79. package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
  80. package/dist/webhook-integration/event-webhook.controller.js +10 -0
  81. package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
  82. package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
  83. package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
  84. package/dist/webhook-integration/event-webhook.service.js +30 -0
  85. package/dist/webhook-integration/event-webhook.service.js.map +1 -1
  86. package/dist/webhook-integration/webhook-integration.controller.d.ts +1 -0
  87. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  88. package/dist/webhook-integration/webhook-integration.controller.js +10 -0
  89. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  90. package/dist/webhook-integration/webhook-integration.service.d.ts +2 -1
  91. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  92. package/dist/webhook-integration/webhook-integration.service.js +62 -44
  93. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  94. package/dist/whatsapp-profile/dto/create.dto.d.ts +11 -0
  95. package/dist/whatsapp-profile/dto/create.dto.d.ts.map +1 -0
  96. package/dist/whatsapp-profile/dto/create.dto.js +55 -0
  97. package/dist/whatsapp-profile/dto/create.dto.js.map +1 -0
  98. package/dist/whatsapp-profile/dto/update.dto.d.ts +6 -0
  99. package/dist/whatsapp-profile/dto/update.dto.d.ts.map +1 -0
  100. package/dist/whatsapp-profile/dto/update.dto.js +9 -0
  101. package/dist/whatsapp-profile/dto/update.dto.js.map +1 -0
  102. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts +54 -0
  103. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts.map +1 -0
  104. package/dist/whatsapp-profile/whatsapp-profile.controller.js +85 -0
  105. package/dist/whatsapp-profile/whatsapp-profile.controller.js.map +1 -0
  106. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts +3 -0
  107. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts.map +1 -0
  108. package/dist/whatsapp-profile/whatsapp-profile.module.js +26 -0
  109. package/dist/whatsapp-profile/whatsapp-profile.module.js.map +1 -0
  110. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts +63 -0
  111. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts.map +1 -0
  112. package/dist/whatsapp-profile/whatsapp-profile.service.js +138 -0
  113. package/dist/whatsapp-profile/whatsapp-profile.service.js.map +1 -0
  114. package/hedhog/data/file_provider.yaml +9 -1
  115. package/hedhog/data/integration_provider.yaml +132 -0
  116. package/hedhog/data/integration_type.yaml +29 -0
  117. package/hedhog/data/menu.yaml +15 -14
  118. package/hedhog/data/role.yaml +8 -0
  119. package/hedhog/data/route.yaml +66 -15
  120. package/hedhog/data/setting_group.yaml +30 -191
  121. package/hedhog/data/setting_subgroup.yaml +5 -13
  122. package/hedhog/data/whatsapp_profile.yaml +6 -0
  123. package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
  124. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +579 -204
  125. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1662 -0
  126. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +233 -108
  127. package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +3 -822
  128. package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
  129. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
  130. package/hedhog/frontend/messages/en.json +172 -0
  131. package/hedhog/frontend/messages/pt.json +172 -0
  132. package/hedhog/table/integration_profile.yaml +34 -0
  133. package/hedhog/table/integration_provider.yaml +23 -0
  134. package/hedhog/table/integration_type.yaml +19 -0
  135. package/hedhog/table/webhook_action.yaml +85 -85
  136. package/hedhog/table/whatsapp_profile.yaml +26 -0
  137. package/package.json +2 -2
  138. package/src/ai/ai.service.ts +35 -153
  139. package/src/core.module.ts +3 -3
  140. package/src/file/file.service.ts +60 -76
  141. package/src/file/provider/provider.enum.ts +1 -0
  142. package/src/file/provider/provider.factory.ts +3 -0
  143. package/src/file/provider/spaces.provider.ts +261 -0
  144. package/src/index.ts +6 -3
  145. package/src/integration-profile/dto/create.dto.ts +44 -0
  146. package/src/integration-profile/dto/export.dto.ts +15 -0
  147. package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
  148. package/src/integration-profile/dto/update.dto.ts +4 -0
  149. package/src/integration-profile/integration-profile.controller.ts +129 -0
  150. package/src/integration-profile/integration-profile.module.ts +16 -0
  151. package/src/integration-profile/integration-profile.service.ts +788 -0
  152. package/src/integration-profile/integration-profile.utils.ts +156 -0
  153. package/src/mail/mail.module.ts +27 -18
  154. package/src/mail/mail.service.ts +31 -60
  155. package/src/mcp/mcp.module.ts +2 -2
  156. package/src/mcp/tools/core-mail-profile.mcp-tools.ts +10 -69
  157. package/src/mcp-chat/mcp-chat.service.ts +23 -20
  158. package/src/setting/setting.service.ts +0 -2
  159. package/src/webhook-integration/event-webhook.controller.ts +55 -50
  160. package/src/webhook-integration/event-webhook.service.ts +422 -384
  161. package/src/webhook-integration/webhook-integration.controller.ts +5 -0
  162. package/src/webhook-integration/webhook-integration.service.ts +74 -46
  163. package/src/whatsapp-profile/dto/create.dto.ts +36 -0
  164. package/src/whatsapp-profile/dto/update.dto.ts +4 -0
  165. package/src/whatsapp-profile/whatsapp-profile.controller.ts +51 -0
  166. package/src/whatsapp-profile/whatsapp-profile.module.ts +13 -0
  167. package/src/whatsapp-profile/whatsapp-profile.service.ts +160 -0
@@ -0,0 +1,19 @@
1
+ columns:
2
+ - type: pk
3
+ - type: slug
4
+ - name: name
5
+ type: locale_varchar
6
+ length: 127
7
+ locale:
8
+ en: Name
9
+ pt: Nome
10
+ - name: icon
11
+ type: varchar
12
+ length: 127
13
+ isNullable: true
14
+ - type: created_at
15
+ - type: updated_at
16
+ indices:
17
+ - columns:
18
+ - slug
19
+ isUnique: true
@@ -1,85 +1,85 @@
1
- columns:
2
- - type: pk
3
- - type: fk
4
- name: webhook_integration_id
5
- references:
6
- table: webhook_integration
7
- column: id
8
- onDelete: cascade
9
- onUpdate: cascade
10
- - name: type
11
- type: enum
12
- enum:
13
- - email
14
- - whatsapp_evolution
15
- - name: name
16
- type: varchar
17
- length: 127
18
- - name: order
19
- type: int
20
- default: 0
21
- - name: status
22
- type: enum
23
- enum:
24
- - active
25
- - inactive
26
- default: active
27
- - type: fk
28
- name: mail_profile_id
29
- isNullable: true
30
- references:
31
- table: mail_profile
32
- column: id
33
- onDelete: set null
34
- onUpdate: cascade
35
- - type: fk
36
- name: mail_id
37
- isNullable: true
38
- references:
39
- table: mail
40
- column: id
41
- onDelete: set null
42
- onUpdate: cascade
43
- - name: email_to
44
- type: text
45
- isNullable: true
46
- - name: email_cc
47
- type: text
48
- isNullable: true
49
- - name: email_bcc
50
- type: text
51
- isNullable: true
52
- - name: whatsapp_target_type
53
- type: enum
54
- enum:
55
- - phone
56
- - group
57
- isNullable: true
58
- - name: whatsapp_target
59
- type: varchar
60
- length: 255
61
- isNullable: true
62
- - name: whatsapp_template
63
- type: text
64
- isNullable: true
65
- - name: whatsapp_instance
66
- type: varchar
67
- length: 127
68
- isNullable: true
69
- - name: whatsapp_base_url
70
- type: varchar
71
- length: 255
72
- isNullable: true
73
- - name: whatsapp_token
74
- type: text
75
- isNullable: true
76
- - type: created_at
77
- - type: updated_at
78
- indices:
79
- - columns:
80
- - webhook_integration_id
81
- - columns:
82
- - type
83
- - columns:
84
- - status
85
-
1
+ columns:
2
+ - type: pk
3
+ - type: fk
4
+ name: webhook_integration_id
5
+ references:
6
+ table: webhook_integration
7
+ column: id
8
+ onDelete: cascade
9
+ onUpdate: cascade
10
+ - name: type
11
+ type: enum
12
+ enum:
13
+ - email
14
+ - whatsapp_evolution
15
+ - name: name
16
+ type: varchar
17
+ length: 127
18
+ - name: order
19
+ type: int
20
+ default: 0
21
+ - name: status
22
+ type: enum
23
+ enum:
24
+ - active
25
+ - inactive
26
+ default: active
27
+ - type: fk
28
+ name: mail_profile_id
29
+ isNullable: true
30
+ references:
31
+ table: integration_profile
32
+ column: id
33
+ onDelete: set null
34
+ onUpdate: cascade
35
+ - type: fk
36
+ name: mail_id
37
+ isNullable: true
38
+ references:
39
+ table: mail
40
+ column: id
41
+ onDelete: set null
42
+ onUpdate: cascade
43
+ - name: email_to
44
+ type: text
45
+ isNullable: true
46
+ - name: email_cc
47
+ type: text
48
+ isNullable: true
49
+ - name: email_bcc
50
+ type: text
51
+ isNullable: true
52
+ - name: whatsapp_target_type
53
+ type: enum
54
+ enum:
55
+ - phone
56
+ - group
57
+ isNullable: true
58
+ - name: whatsapp_target
59
+ type: varchar
60
+ length: 255
61
+ isNullable: true
62
+ - name: whatsapp_template
63
+ type: text
64
+ isNullable: true
65
+ - name: whatsapp_instance
66
+ type: varchar
67
+ length: 127
68
+ isNullable: true
69
+ - name: whatsapp_base_url
70
+ type: varchar
71
+ length: 255
72
+ isNullable: true
73
+ - name: whatsapp_token
74
+ type: text
75
+ isNullable: true
76
+ - type: created_at
77
+ - type: updated_at
78
+ indices:
79
+ - columns:
80
+ - webhook_integration_id
81
+ - columns:
82
+ - type
83
+ - columns:
84
+ - status
85
+
@@ -0,0 +1,26 @@
1
+ columns:
2
+ - type: pk
3
+ - type: slug
4
+ - name: name
5
+ type: varchar
6
+ length: 127
7
+ - name: provider
8
+ type: enum
9
+ enum:
10
+ - WHATSAPP_API
11
+ default: WHATSAPP_API
12
+ - name: host
13
+ type: varchar
14
+ length: 255
15
+ - name: token
16
+ type: varchar
17
+ length: 255
18
+ - name: instance_name
19
+ type: varchar
20
+ length: 127
21
+ - type: created_at
22
+ - type: updated_at
23
+ indices:
24
+ - columns:
25
+ - slug
26
+ isUnique: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/core",
3
- "version": "0.0.354",
3
+ "version": "0.0.356",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -34,8 +34,8 @@
34
34
  "@modelcontextprotocol/sdk": "^1.12.0",
35
35
  "@hed-hog/api-locale": "0.0.14",
36
36
  "@hed-hog/api-mail": "0.0.9",
37
- "@hed-hog/api-pagination": "0.0.7",
38
37
  "@hed-hog/api-types": "0.0.1",
38
+ "@hed-hog/api-pagination": "0.0.7",
39
39
  "@hed-hog/api": "0.0.8",
40
40
  "@hed-hog/api-prisma": "0.0.6"
41
41
  },
@@ -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 { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
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(): void {
61
- this.integrationApi.subscribe({
62
- eventName: 'core.setting.changed',
63
- consumerName: 'core.ai-provider-key-validator',
64
- priority: 0,
65
- handler: async (event) => {
66
- const slug = String(event.payload?.slug || '').trim();
67
-
68
- if (!this.isAiProviderKeySlug(slug)) {
69
- return;
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 isAiProviderKeySlug(slug: string): slug is AiProviderKeySettingSlug {
427
- return slug === 'ai-openai-api-key' || slug === 'ai-gemini-api-key';
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
- return true;
496
- } catch (error) {
497
- this.logger.warn(
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
- private async validateGeminiKey(apiKey?: string | null): Promise<boolean> {
505
- const normalizedKey = String(apiKey || '').trim();
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 (!normalizedKey) {
508
- return false;
431
+ if (!profile) {
432
+ throw new BadRequestException(`AI profile ${profileId} not found.`);
509
433
  }
510
434
 
511
- try {
512
- await axios.get('https://generativelanguage.googleapis.com/v1beta/models', {
513
- params: {
514
- key: normalizedKey,
515
- pageSize: 1,
516
- },
517
- timeout: 5000,
518
- });
435
+ const { apiKey } = buildAiConfigFromIntegration(
436
+ profile.integration_provider.slug,
437
+ profile.config,
438
+ );
519
439
 
520
- return true;
521
- } catch (error) {
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
- private async getApiKeys() {
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 { openai } = await this.getApiKeys();
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 { openai } = await this.getApiKeys();
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 { openai } = await this.getApiKeys();
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 { gemini } = await this.getApiKeys();
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
 
@@ -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(() => MailProfileModule),
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
- MailProfileModule,
89
+ IntegrationProfileModule,
90
90
  RouteModule,
91
91
  RoleModule,
92
92
  MenuModule,