@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
@@ -61,6 +61,11 @@ export class WebhookIntegrationController {
61
61
  return this.service.regenerateToken(id);
62
62
  }
63
63
 
64
+ @Post(':id/duplicate')
65
+ duplicate(@Param('id', ParseIntPipe) id: number) {
66
+ return this.service.duplicate(id);
67
+ }
68
+
64
69
  @Get(':id/action')
65
70
  listActions(@Param('id', ParseIntPipe) id: number) {
66
71
  return this.service.listActions(id);
@@ -12,6 +12,11 @@ import {
12
12
  import { EventEmitter } from 'events';
13
13
  import { Request, Response } from 'express';
14
14
  import { firstValueFrom } from 'rxjs';
15
+ import {
16
+ buildMailConfigFromIntegration,
17
+ getFromAddress,
18
+ getReplyToAddress,
19
+ } from '../integration-profile/integration-profile.utils';
15
20
  import { MailService } from '../mail/mail.service';
16
21
  import { SettingService } from '../setting/setting.service';
17
22
  import {
@@ -203,6 +208,66 @@ export class WebhookIntegrationService {
203
208
  };
204
209
  }
205
210
 
211
+ async duplicate(id: number) {
212
+ const original = await this.get(id);
213
+
214
+ const newSlug = await this.generateUniqueSlug(original.slug, this.integrations);
215
+
216
+ let plainToken: string | null = null;
217
+ let tokenHash: string | null = null;
218
+ if (original.require_token) {
219
+ plainToken = createPlainToken();
220
+ tokenHash = hashToken(plainToken);
221
+ }
222
+
223
+ const record = await this.integrations.create({
224
+ data: {
225
+ slug: newSlug,
226
+ name: `${original.name} (copy)`,
227
+ description: original.description,
228
+ public_uuid: createPublicUuid(),
229
+ status: original.status,
230
+ require_token: original.require_token,
231
+ token_hash: tokenHash,
232
+ allowed_ips: original.allowed_ips,
233
+ body_schema: original.body_schema,
234
+ webhook_action: {
235
+ create: (original.webhook_action ?? []).map((a: any) => ({
236
+ type: a.type,
237
+ name: a.name,
238
+ order: a.order,
239
+ status: a.status,
240
+ mail_profile_id: a.mail_profile_id,
241
+ mail_id: a.mail_id,
242
+ email_to: a.email_to,
243
+ email_cc: a.email_cc,
244
+ email_bcc: a.email_bcc,
245
+ whatsapp_target_type: a.whatsapp_target_type,
246
+ whatsapp_target: a.whatsapp_target,
247
+ whatsapp_template: a.whatsapp_template,
248
+ whatsapp_instance: a.whatsapp_instance,
249
+ whatsapp_base_url: a.whatsapp_base_url,
250
+ whatsapp_token: a.whatsapp_token,
251
+ })),
252
+ },
253
+ },
254
+ });
255
+
256
+ return { ...(await this.withPublicUrl(record)), plainToken };
257
+ }
258
+
259
+ private async generateUniqueSlug(base: string, table: any): Promise<string> {
260
+ const candidate = `${base}-copy`;
261
+ const existing = await table.findUnique({ where: { slug: candidate } });
262
+ if (!existing) return candidate;
263
+
264
+ for (let i = 2; ; i++) {
265
+ const next = `${base}-copy-${i}`;
266
+ const taken = await table.findUnique({ where: { slug: next } });
267
+ if (!taken) return next;
268
+ }
269
+ }
270
+
206
271
  private async getApplicationBaseUrl() {
207
272
  const settings = await this.settingService.getSettingValues([
208
273
  'api-url',
@@ -539,8 +604,9 @@ export class WebhookIntegrationService {
539
604
  private async executeEmailAction(action: any, body: any) {
540
605
  this.validateActionConfiguration(action);
541
606
 
542
- const profile = await (this.prisma as any).mail_profile.findUnique({
607
+ const profile = await (this.prisma as any).integration_profile.findUnique({
543
608
  where: { id: Number(action.mail_profile_id) },
609
+ include: { integration_provider: { select: { slug: true } } },
544
610
  });
545
611
  const mail = await (this.prisma as any).mail.findUnique({
546
612
  where: { id: Number(action.mail_id) },
@@ -558,15 +624,12 @@ export class WebhookIntegrationService {
558
624
  }
559
625
 
560
626
  const template = mail.mail_locale[0];
561
- const config = this.buildMailConfig(profile);
562
- const sender = profile.from_name
563
- ? `${profile.from_name} <${profile.from_email}>`
564
- : profile.from_email;
565
- const replyTo = profile.reply_to_email
566
- ? profile.reply_to_name
567
- ? `${profile.reply_to_name} <${profile.reply_to_email}>`
568
- : profile.reply_to_email
569
- : undefined;
627
+ const config = buildMailConfigFromIntegration(
628
+ profile.integration_provider.slug,
629
+ profile.config,
630
+ );
631
+ const sender = getFromAddress(profile.config);
632
+ const replyTo = getReplyToAddress(profile.config);
570
633
 
571
634
  const renderedTo = String(renderTemplate(action.email_to, body) ?? '').trim();
572
635
  const renderedCc = action.email_cc
@@ -1098,40 +1161,5 @@ export class WebhookIntegrationService {
1098
1161
  return Number(value);
1099
1162
  }
1100
1163
 
1101
- private buildMailConfig(profile: any) {
1102
- switch (profile.provider) {
1103
- case 'SMTP':
1104
- return {
1105
- global: true,
1106
- type: 'SMTP',
1107
- host: profile.smtp_host,
1108
- port: Number(profile.smtp_port || 587),
1109
- secure: Boolean(profile.smtp_secure),
1110
- username: profile.smtp_username || '',
1111
- password: profile.smtp_password || '',
1112
- };
1113
- case 'GMAIL':
1114
- return {
1115
- global: true,
1116
- type: 'GMAIL',
1117
- clientId: profile.gmail_client_id,
1118
- clientSecret: profile.gmail_client_secret,
1119
- refreshToken: profile.gmail_refresh_token,
1120
- from: profile.from_email,
1121
- };
1122
- case 'SES':
1123
- return {
1124
- global: true,
1125
- type: 'SES',
1126
- region: profile.ses_region,
1127
- accessKeyId: profile.ses_access_key_id,
1128
- secretAccessKey: profile.ses_secret_access_key,
1129
- from: profile.from_email,
1130
- };
1131
- default:
1132
- throw new BadRequestException(
1133
- `Invalid mail profile provider: ${profile.provider}`,
1134
- );
1135
- }
1136
- }
1137
1164
  }
1165
+
@@ -0,0 +1,36 @@
1
+ import { getLocaleText } from '@hed-hog/api-locale';
2
+ import { Transform } from 'class-transformer';
3
+ import { IsIn, IsString, MaxLength } from 'class-validator';
4
+
5
+ const providerOptions = ['WHATSAPP_API'] as const;
6
+
7
+ export class CreateDTO {
8
+ @IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
9
+ @MaxLength(127)
10
+ @Transform(({ value }) => String(value ?? '').trim())
11
+ slug: string;
12
+
13
+ @IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
14
+ @MaxLength(127)
15
+ @Transform(({ value }) => String(value ?? '').trim())
16
+ name: string;
17
+
18
+ @IsIn(providerOptions)
19
+ @Transform(({ value }) => String(value ?? '').trim().toUpperCase())
20
+ provider: (typeof providerOptions)[number];
21
+
22
+ @IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
23
+ @MaxLength(255)
24
+ @Transform(({ value }) => String(value ?? '').trim())
25
+ host: string;
26
+
27
+ @IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
28
+ @MaxLength(255)
29
+ @Transform(({ value }) => String(value ?? '').trim())
30
+ token: string;
31
+
32
+ @IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
33
+ @MaxLength(127)
34
+ @Transform(({ value }) => String(value ?? '').trim())
35
+ instance_name: string;
36
+ }
@@ -0,0 +1,4 @@
1
+ import { PartialType } from '@nestjs/mapped-types';
2
+ import { CreateDTO } from './create.dto';
3
+
4
+ export class UpdateDTO extends PartialType(CreateDTO) {}
@@ -0,0 +1,51 @@
1
+ import { DeleteDTO, Role } from '@hed-hog/api';
2
+ import { Pagination } from '@hed-hog/api-pagination';
3
+ import {
4
+ Body,
5
+ Controller,
6
+ Delete,
7
+ Get,
8
+ Inject,
9
+ Param,
10
+ ParseIntPipe,
11
+ Patch,
12
+ Post,
13
+ forwardRef,
14
+ } from '@nestjs/common';
15
+ import { CreateDTO } from './dto/create.dto';
16
+ import { UpdateDTO } from './dto/update.dto';
17
+ import { WhatsAppProfileService } from './whatsapp-profile.service';
18
+
19
+ @Role()
20
+ @Controller('whatsapp-profile')
21
+ export class WhatsAppProfileController {
22
+ constructor(
23
+ @Inject(forwardRef(() => WhatsAppProfileService))
24
+ private readonly whatsappProfileService: WhatsAppProfileService,
25
+ ) {}
26
+
27
+ @Get()
28
+ async list(@Pagination() paginationParams) {
29
+ return this.whatsappProfileService.list(paginationParams);
30
+ }
31
+
32
+ @Get(':id')
33
+ async get(@Param('id', ParseIntPipe) id: number) {
34
+ return this.whatsappProfileService.get(id);
35
+ }
36
+
37
+ @Post()
38
+ async create(@Body() data: CreateDTO) {
39
+ return this.whatsappProfileService.create(data);
40
+ }
41
+
42
+ @Patch(':id')
43
+ async update(@Param('id', ParseIntPipe) id: number, @Body() data: UpdateDTO) {
44
+ return this.whatsappProfileService.update({ id, data });
45
+ }
46
+
47
+ @Delete()
48
+ async delete(@Body() data: DeleteDTO) {
49
+ return this.whatsappProfileService.delete(data);
50
+ }
51
+ }
@@ -0,0 +1,13 @@
1
+ import { PaginationModule } from '@hed-hog/api-pagination';
2
+ import { PrismaModule } from '@hed-hog/api-prisma';
3
+ import { forwardRef, Module } from '@nestjs/common';
4
+ import { WhatsAppProfileController } from './whatsapp-profile.controller';
5
+ import { WhatsAppProfileService } from './whatsapp-profile.service';
6
+
7
+ @Module({
8
+ imports: [forwardRef(() => PrismaModule), forwardRef(() => PaginationModule)],
9
+ controllers: [WhatsAppProfileController],
10
+ providers: [WhatsAppProfileService],
11
+ exports: [WhatsAppProfileService],
12
+ })
13
+ export class WhatsAppProfileModule {}
@@ -0,0 +1,160 @@
1
+ import { DeleteDTO } from '@hed-hog/api';
2
+ import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
3
+ import { PrismaService } from '@hed-hog/api-prisma';
4
+ import {
5
+ BadRequestException,
6
+ Inject,
7
+ Injectable,
8
+ NotFoundException,
9
+ forwardRef,
10
+ } from '@nestjs/common';
11
+ import { CreateDTO } from './dto/create.dto';
12
+ import { UpdateDTO } from './dto/update.dto';
13
+
14
+ @Injectable()
15
+ export class WhatsAppProfileService {
16
+ constructor(
17
+ @Inject(forwardRef(() => PrismaService))
18
+ private readonly prismaService: PrismaService,
19
+ @Inject(forwardRef(() => PaginationService))
20
+ private readonly paginationService: PaginationService,
21
+ ) {}
22
+
23
+ async list(paginationParams: PaginationDTO) {
24
+ const fields = ['slug', 'name', 'host', 'instance_name'];
25
+ const OR = this.prismaService.createInsensitiveSearch(fields, paginationParams);
26
+
27
+ return this.paginationService.paginate(
28
+ this.prismaService.whatsapp_profile,
29
+ paginationParams,
30
+ {
31
+ where: OR.length > 0 ? { OR } : {},
32
+ select: {
33
+ id: true,
34
+ slug: true,
35
+ name: true,
36
+ provider: true,
37
+ host: true,
38
+ token: true,
39
+ instance_name: true,
40
+ created_at: true,
41
+ updated_at: true,
42
+ },
43
+ orderBy: [{ updated_at: 'desc' }, { id: 'desc' }],
44
+ },
45
+ );
46
+ }
47
+
48
+ async get(id: number) {
49
+ const profile = await this.prismaService.whatsapp_profile.findUnique({
50
+ where: { id },
51
+ });
52
+
53
+ if (!profile) {
54
+ throw new NotFoundException(`WhatsApp profile with id ${id} not found.`);
55
+ }
56
+
57
+ return profile;
58
+ }
59
+
60
+ async create(data: CreateDTO) {
61
+ await this.ensureSlugIsAvailable(data.slug);
62
+ this.validateProviderFields(data as unknown as Record<string, unknown>);
63
+
64
+ return this.prismaService.whatsapp_profile.create({
65
+ data: this.normalizeData(data as unknown as Record<string, unknown>) as any,
66
+ });
67
+ }
68
+
69
+ async update({ id, data }: { id: number; data: UpdateDTO }) {
70
+ const existing = await this.prismaService.whatsapp_profile.findUnique({
71
+ where: { id },
72
+ });
73
+
74
+ if (!existing) {
75
+ throw new NotFoundException(`WhatsApp profile with id ${id} not found.`);
76
+ }
77
+
78
+ if (data.slug && data.slug !== existing.slug) {
79
+ await this.ensureSlugIsAvailable(data.slug);
80
+ }
81
+
82
+ const merged = {
83
+ ...existing,
84
+ ...data,
85
+ } satisfies Record<string, unknown>;
86
+
87
+ this.validateProviderFields(merged);
88
+
89
+ return this.prismaService.whatsapp_profile.update({
90
+ where: { id },
91
+ data: this.normalizeData(merged) as any,
92
+ });
93
+ }
94
+
95
+ async delete({ ids }: DeleteDTO): Promise<{ count: number }> {
96
+ if (!ids?.length) {
97
+ throw new BadRequestException('You must select at least one item to delete.');
98
+ }
99
+
100
+ return this.prismaService.whatsapp_profile.deleteMany({
101
+ where: {
102
+ id: {
103
+ in: ids,
104
+ },
105
+ },
106
+ });
107
+ }
108
+
109
+ private async ensureSlugIsAvailable(slug: string) {
110
+ const existing = await this.prismaService.whatsapp_profile.findUnique({
111
+ where: { slug },
112
+ select: { id: true },
113
+ });
114
+
115
+ if (existing) {
116
+ throw new BadRequestException(
117
+ `WhatsApp profile with slug "${slug}" already exists.`,
118
+ );
119
+ }
120
+ }
121
+
122
+ private validateProviderFields(input: Record<string, unknown>) {
123
+ const provider = String(input.provider ?? '').toUpperCase();
124
+
125
+ if (!provider) {
126
+ throw new BadRequestException('Provider is required.');
127
+ }
128
+
129
+ if (provider !== 'WHATSAPP_API') {
130
+ throw new BadRequestException(`Invalid provider: ${provider}`);
131
+ }
132
+
133
+ if (!String(input.host ?? '').trim()) {
134
+ throw new BadRequestException('WhatsApp host is required.');
135
+ }
136
+
137
+ if (!String(input.token ?? '').trim()) {
138
+ throw new BadRequestException('WhatsApp token is required.');
139
+ }
140
+
141
+ if (!String(input.instance_name ?? '').trim()) {
142
+ throw new BadRequestException('WhatsApp instance name is required.');
143
+ }
144
+ }
145
+
146
+ private normalizeData(input: Record<string, unknown>) {
147
+ return {
148
+ slug: this.normalizeString(input.slug),
149
+ name: this.normalizeString(input.name),
150
+ provider: 'WHATSAPP_API',
151
+ host: this.normalizeString(input.host),
152
+ token: this.normalizeString(input.token),
153
+ instance_name: this.normalizeString(input.instance_name),
154
+ };
155
+ }
156
+
157
+ private normalizeString(value: unknown) {
158
+ return String(value ?? '').trim();
159
+ }
160
+ }