@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
|
@@ -8,9 +8,13 @@ import {
|
|
|
8
8
|
Inject,
|
|
9
9
|
Injectable,
|
|
10
10
|
Logger,
|
|
11
|
-
NotFoundException
|
|
11
|
+
NotFoundException,
|
|
12
|
+
OnModuleDestroy,
|
|
13
|
+
OnModuleInit,
|
|
12
14
|
} from '@nestjs/common';
|
|
15
|
+
import { randomUUID } from 'node:crypto';
|
|
13
16
|
import * as pako from 'pako';
|
|
17
|
+
import { createClient, type RedisClientType } from 'redis';
|
|
14
18
|
import { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
|
|
15
19
|
import { CreateDTO } from './dto/create.dto';
|
|
16
20
|
import { DeleteDTO } from './dto/delete.dto';
|
|
@@ -27,11 +31,34 @@ type SettingChangeEventInput = {
|
|
|
27
31
|
source: string;
|
|
28
32
|
};
|
|
29
33
|
|
|
34
|
+
type SettingsVersionMessage = {
|
|
35
|
+
originInstanceId: string;
|
|
36
|
+
version: number;
|
|
37
|
+
slugs: string[];
|
|
38
|
+
};
|
|
39
|
+
|
|
30
40
|
@Injectable()
|
|
31
|
-
export class SettingService {
|
|
41
|
+
export class SettingService implements OnModuleInit, OnModuleDestroy {
|
|
32
42
|
|
|
33
43
|
private readonly logger = new Logger(SettingService.name);
|
|
34
44
|
private cachedSettings: Record<string, any> = {};
|
|
45
|
+
private readonly instanceId = randomUUID();
|
|
46
|
+
private readonly redisChannel = 'core:settings:version-changed';
|
|
47
|
+
private readonly redisUrl = String(process.env.REDIS_URL || '').trim();
|
|
48
|
+
private readonly settingsVersionCheckIntervalMs = Math.max(
|
|
49
|
+
1000,
|
|
50
|
+
Number(process.env.SETTINGS_VERSION_CHECK_INTERVAL_MS || 5000),
|
|
51
|
+
);
|
|
52
|
+
private localSettingsVersion = 0;
|
|
53
|
+
private lastSettingsVersionCheckAt = 0;
|
|
54
|
+
private redisPublisher: RedisClientType | null = null;
|
|
55
|
+
private redisSubscriber: RedisClientType | null = null;
|
|
56
|
+
private readonly redisErrorLogCooldownMs = Math.max(
|
|
57
|
+
1000,
|
|
58
|
+
Number(process.env.REDIS_SETTINGS_ERROR_LOG_COOLDOWN_MS || 30000),
|
|
59
|
+
);
|
|
60
|
+
private lastRedisSubscriberErrorLogAt = 0;
|
|
61
|
+
private lastRedisPublisherErrorLogAt = 0;
|
|
35
62
|
|
|
36
63
|
constructor(
|
|
37
64
|
@Inject(forwardRef(() => PrismaService))
|
|
@@ -44,6 +71,231 @@ export class SettingService {
|
|
|
44
71
|
private readonly integrationApi: IntegrationDeveloperApiService,
|
|
45
72
|
) { }
|
|
46
73
|
|
|
74
|
+
async onModuleInit() {
|
|
75
|
+
await this.syncSettingsVersionFromDatabase();
|
|
76
|
+
await this.initializeRedisSync();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async onModuleDestroy() {
|
|
80
|
+
await Promise.allSettled([
|
|
81
|
+
this.safeCloseRedisClient(this.redisSubscriber),
|
|
82
|
+
this.safeCloseRedisClient(this.redisPublisher),
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private async safeCloseRedisClient(client: RedisClientType | null) {
|
|
87
|
+
if (!client || !client.isOpen) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await client.quit();
|
|
93
|
+
} catch {
|
|
94
|
+
try {
|
|
95
|
+
client.disconnect();
|
|
96
|
+
} catch {
|
|
97
|
+
// ignore shutdown errors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private logRedisClientError(kind: 'subscriber' | 'publisher', error: unknown) {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
const lastLogAt =
|
|
105
|
+
kind === 'subscriber'
|
|
106
|
+
? this.lastRedisSubscriberErrorLogAt
|
|
107
|
+
: this.lastRedisPublisherErrorLogAt;
|
|
108
|
+
|
|
109
|
+
if (now - lastLogAt < this.redisErrorLogCooldownMs) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (kind === 'subscriber') {
|
|
114
|
+
this.lastRedisSubscriberErrorLogAt = now;
|
|
115
|
+
} else {
|
|
116
|
+
this.lastRedisPublisherErrorLogAt = now;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
120
|
+
this.logger.warn(`Redis settings ${kind} error: ${message}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private async initializeRedisSync() {
|
|
124
|
+
if (!this.redisUrl) {
|
|
125
|
+
this.logger.log(
|
|
126
|
+
'Redis settings sync disabled because REDIS_URL is not configured.',
|
|
127
|
+
);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
this.redisSubscriber = createClient({
|
|
133
|
+
url: this.redisUrl,
|
|
134
|
+
socket: {
|
|
135
|
+
reconnectStrategy: (retries) => Math.min(retries * 250, 5000),
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
this.redisPublisher = createClient({
|
|
139
|
+
url: this.redisUrl,
|
|
140
|
+
socket: {
|
|
141
|
+
reconnectStrategy: (retries) => Math.min(retries * 250, 5000),
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
this.redisSubscriber.on('error', (error) => {
|
|
146
|
+
this.logRedisClientError('subscriber', error);
|
|
147
|
+
});
|
|
148
|
+
this.redisPublisher.on('error', (error) => {
|
|
149
|
+
this.logRedisClientError('publisher', error);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await this.redisSubscriber.connect();
|
|
153
|
+
await this.redisPublisher.connect();
|
|
154
|
+
await this.redisSubscriber.subscribe(this.redisChannel, async (message) => {
|
|
155
|
+
await this.handleRedisSettingsVersionMessage(message);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
this.logger.log(
|
|
159
|
+
`Redis settings sync enabled on channel ${this.redisChannel}`,
|
|
160
|
+
);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
this.logger.warn(
|
|
163
|
+
`Failed to initialize Redis settings sync: ${error instanceof Error ? error.message : String(error)}`,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
await Promise.allSettled([
|
|
167
|
+
this.safeCloseRedisClient(this.redisSubscriber),
|
|
168
|
+
this.safeCloseRedisClient(this.redisPublisher),
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
this.redisSubscriber = null;
|
|
172
|
+
this.redisPublisher = null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private async handleRedisSettingsVersionMessage(message: string) {
|
|
177
|
+
let payload: SettingsVersionMessage;
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
payload = JSON.parse(message) as SettingsVersionMessage;
|
|
181
|
+
} catch {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!payload || payload.originInstanceId === this.instanceId) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!Number.isFinite(payload.version) || payload.version <= this.localSettingsVersion) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.localSettingsVersion = payload.version;
|
|
194
|
+
this.lastSettingsVersionCheckAt = Date.now();
|
|
195
|
+
this.clearCache();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private async ensureSettingsVersionState() {
|
|
199
|
+
await this.prismaService.$executeRawUnsafe(`
|
|
200
|
+
INSERT INTO "setting_runtime_state" ("scope", "version", "updated_at")
|
|
201
|
+
VALUES ('global', 0, NOW())
|
|
202
|
+
ON CONFLICT ("scope") DO NOTHING
|
|
203
|
+
`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private parseVersionValue(value: unknown): number {
|
|
207
|
+
if (typeof value === 'number') {
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (typeof value === 'bigint') {
|
|
212
|
+
return Number(value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (typeof value === 'string') {
|
|
216
|
+
return Number(value);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private async getSettingsVersionFromDatabase(): Promise<number> {
|
|
223
|
+
await this.ensureSettingsVersionState();
|
|
224
|
+
|
|
225
|
+
const rows = await this.prismaService.$queryRawUnsafe<Array<{ version: unknown }>>(`
|
|
226
|
+
SELECT "version"
|
|
227
|
+
FROM "setting_runtime_state"
|
|
228
|
+
WHERE "scope" = 'global'
|
|
229
|
+
LIMIT 1
|
|
230
|
+
`);
|
|
231
|
+
|
|
232
|
+
return this.parseVersionValue(rows[0]?.version);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private async syncSettingsVersionFromDatabase() {
|
|
236
|
+
this.localSettingsVersion = await this.getSettingsVersionFromDatabase();
|
|
237
|
+
this.lastSettingsVersionCheckAt = Date.now();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private async bumpSettingsVersion(): Promise<number> {
|
|
241
|
+
await this.ensureSettingsVersionState();
|
|
242
|
+
|
|
243
|
+
const rows = await this.prismaService.$queryRawUnsafe<Array<{ version: unknown }>>(`
|
|
244
|
+
UPDATE "setting_runtime_state"
|
|
245
|
+
SET "version" = "version" + 1,
|
|
246
|
+
"updated_at" = NOW()
|
|
247
|
+
WHERE "scope" = 'global'
|
|
248
|
+
RETURNING "version"
|
|
249
|
+
`);
|
|
250
|
+
|
|
251
|
+
const nextVersion = this.parseVersionValue(rows[0]?.version);
|
|
252
|
+
this.localSettingsVersion = nextVersion;
|
|
253
|
+
this.lastSettingsVersionCheckAt = Date.now();
|
|
254
|
+
return nextVersion;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private async ensureCacheVersionFresh() {
|
|
258
|
+
const now = Date.now();
|
|
259
|
+
if (now - this.lastSettingsVersionCheckAt < this.settingsVersionCheckIntervalMs) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const currentVersion = await this.getSettingsVersionFromDatabase();
|
|
264
|
+
this.lastSettingsVersionCheckAt = now;
|
|
265
|
+
|
|
266
|
+
if (currentVersion > this.localSettingsVersion) {
|
|
267
|
+
this.localSettingsVersion = currentVersion;
|
|
268
|
+
this.clearCache();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private async publishSettingsVersionChange(slugs: string[]) {
|
|
273
|
+
const filteredSlugs = Array.from(new Set(slugs.filter(Boolean)));
|
|
274
|
+
if (filteredSlugs.length === 0) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const nextVersion = await this.bumpSettingsVersion();
|
|
279
|
+
|
|
280
|
+
if (!this.redisPublisher?.isOpen) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const payload: SettingsVersionMessage = {
|
|
285
|
+
originInstanceId: this.instanceId,
|
|
286
|
+
version: nextVersion,
|
|
287
|
+
slugs: filteredSlugs,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
await this.redisPublisher.publish(this.redisChannel, JSON.stringify(payload));
|
|
292
|
+
} catch (error) {
|
|
293
|
+
this.logger.warn(
|
|
294
|
+
`Failed to publish settings version change: ${error instanceof Error ? error.message : String(error)}`,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
47
299
|
async exportSettings(includeSecrets = false): Promise<Buffer> {
|
|
48
300
|
const settings = await this.prismaService.setting.findMany({
|
|
49
301
|
where: {
|
|
@@ -158,6 +410,7 @@ export class SettingService {
|
|
|
158
410
|
if (transaction.length > 0) {
|
|
159
411
|
await this.prismaService.$transaction(transaction);
|
|
160
412
|
await this.emitSettingChangedEvents(changedSettings);
|
|
413
|
+
await this.publishSettingsVersionChange(changedSettings.map((item) => item.slug));
|
|
161
414
|
}
|
|
162
415
|
|
|
163
416
|
return {
|
|
@@ -206,14 +459,19 @@ export class SettingService {
|
|
|
206
459
|
'password-min-uppercase',
|
|
207
460
|
'password-min-length',
|
|
208
461
|
'mfa-email-code-length',
|
|
209
|
-
'ai-openai-api-key-enabled',
|
|
210
|
-
'ai-gemini-api-key-enabled',
|
|
211
462
|
'mcp-enabled',
|
|
212
463
|
'date-format',
|
|
213
464
|
'time-format',
|
|
214
465
|
'timezone',
|
|
215
466
|
'menu-width',
|
|
467
|
+
'maintenance-mode-enabled',
|
|
216
468
|
'providers',
|
|
469
|
+
'oauth-facebook-enabled',
|
|
470
|
+
'oauth-github-enabled',
|
|
471
|
+
'oauth-google-enabled',
|
|
472
|
+
'oauth-microsoft-enabled',
|
|
473
|
+
'oauth-microsoft-entra-id-enabled',
|
|
474
|
+
'admin-login-page-oauth-providers',
|
|
217
475
|
'disable-authentication-with-email-and-password',
|
|
218
476
|
'contact-allow-company-registration',
|
|
219
477
|
'operations.comment-edit-window',
|
|
@@ -313,6 +571,7 @@ export class SettingService {
|
|
|
313
571
|
|
|
314
572
|
await this.prismaService.$transaction(transaction);
|
|
315
573
|
await this.emitSettingChangedEvents(changedSettings);
|
|
574
|
+
await this.publishSettingsVersionChange(changedSettings.map((item) => item.slug));
|
|
316
575
|
return { success: true };
|
|
317
576
|
}
|
|
318
577
|
|
|
@@ -657,6 +916,8 @@ export class SettingService {
|
|
|
657
916
|
},
|
|
658
917
|
]);
|
|
659
918
|
|
|
919
|
+
await this.publishSettingsVersionChange([createdSetting.slug]);
|
|
920
|
+
|
|
660
921
|
return createdSetting;
|
|
661
922
|
}
|
|
662
923
|
|
|
@@ -728,6 +989,8 @@ export class SettingService {
|
|
|
728
989
|
},
|
|
729
990
|
]);
|
|
730
991
|
|
|
992
|
+
await this.publishSettingsVersionChange([updatedSetting.slug]);
|
|
993
|
+
|
|
731
994
|
// Garantir que o value sobrescreve o valor original
|
|
732
995
|
const result = { ...updatedSetting };
|
|
733
996
|
result.value = this.getValueFormattedByType(updatedSetting.type, updatedSetting.value);
|
|
@@ -772,6 +1035,8 @@ export class SettingService {
|
|
|
772
1035
|
},
|
|
773
1036
|
]);
|
|
774
1037
|
|
|
1038
|
+
await this.publishSettingsVersionChange([updatedSetting.slug]);
|
|
1039
|
+
|
|
775
1040
|
const result = { ...updatedSetting };
|
|
776
1041
|
result.value = this.getValueFormattedByType(updatedSetting.type, updatedSetting.value);
|
|
777
1042
|
return result;
|
|
@@ -857,8 +1122,18 @@ export class SettingService {
|
|
|
857
1122
|
switch (type) {
|
|
858
1123
|
case 'boolean':
|
|
859
1124
|
return value === true || value === 'true' ? 'true' : 'false';
|
|
860
|
-
case 'number':
|
|
861
|
-
|
|
1125
|
+
case 'number': {
|
|
1126
|
+
if (value === undefined || value === null || String(value).trim() === '') {
|
|
1127
|
+
return '';
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const numericValue = Number(value);
|
|
1131
|
+
if (!Number.isFinite(numericValue)) {
|
|
1132
|
+
throw new BadRequestException(`Invalid numeric value for setting: ${value}`);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
return numericValue.toString();
|
|
1136
|
+
}
|
|
862
1137
|
case 'array':
|
|
863
1138
|
case 'json':
|
|
864
1139
|
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
@@ -871,8 +1146,18 @@ export class SettingService {
|
|
|
871
1146
|
switch (type) {
|
|
872
1147
|
case 'boolean':
|
|
873
1148
|
return value === true || value === 'true' ? 'true' : 'false';
|
|
874
|
-
case 'number':
|
|
875
|
-
|
|
1149
|
+
case 'number': {
|
|
1150
|
+
if (value === undefined || value === null || String(value).trim() === '') {
|
|
1151
|
+
return '';
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
const numericValue = Number(value);
|
|
1155
|
+
if (!Number.isFinite(numericValue)) {
|
|
1156
|
+
throw new BadRequestException(`Invalid numeric value for setting: ${value}`);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return numericValue.toString();
|
|
1160
|
+
}
|
|
876
1161
|
case 'array':
|
|
877
1162
|
case 'json':
|
|
878
1163
|
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
@@ -897,6 +1182,7 @@ export class SettingService {
|
|
|
897
1182
|
},
|
|
898
1183
|
select: {
|
|
899
1184
|
id: true,
|
|
1185
|
+
slug: true,
|
|
900
1186
|
},
|
|
901
1187
|
});
|
|
902
1188
|
|
|
@@ -906,13 +1192,19 @@ export class SettingService {
|
|
|
906
1192
|
);
|
|
907
1193
|
}
|
|
908
1194
|
|
|
909
|
-
|
|
1195
|
+
const deleted = await this.prismaService.setting.deleteMany({
|
|
910
1196
|
where: {
|
|
911
1197
|
id: {
|
|
912
1198
|
in: ids,
|
|
913
1199
|
},
|
|
914
1200
|
},
|
|
915
1201
|
});
|
|
1202
|
+
|
|
1203
|
+
if (deleted.count > 0) {
|
|
1204
|
+
await this.publishSettingsVersionChange(existingSettings.map((item) => item.slug));
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
return deleted;
|
|
916
1208
|
}
|
|
917
1209
|
|
|
918
1210
|
async setSettingUserValue(locale:string, user_id: number, slug: string, value: string) {
|
|
@@ -972,6 +1264,10 @@ export class SettingService {
|
|
|
972
1264
|
): Promise<Record<string, any>> {
|
|
973
1265
|
|
|
974
1266
|
const slugs = Array.isArray(slug) ? slug : [slug];
|
|
1267
|
+
if (userId === undefined) {
|
|
1268
|
+
await this.ensureCacheVersionFresh();
|
|
1269
|
+
}
|
|
1270
|
+
|
|
975
1271
|
if (
|
|
976
1272
|
userId === undefined &&
|
|
977
1273
|
this.cachedSettings &&
|
|
@@ -1144,6 +1440,8 @@ export class SettingService {
|
|
|
1144
1440
|
},
|
|
1145
1441
|
]);
|
|
1146
1442
|
|
|
1443
|
+
await this.publishSettingsVersionChange([currentSetting.slug]);
|
|
1444
|
+
|
|
1147
1445
|
return result;
|
|
1148
1446
|
}
|
|
1149
1447
|
}
|
|
@@ -12,12 +12,14 @@ import {
|
|
|
12
12
|
ParseIntPipe,
|
|
13
13
|
Patch,
|
|
14
14
|
Post,
|
|
15
|
+
Req,
|
|
15
16
|
Res,
|
|
16
17
|
UploadedFile,
|
|
17
18
|
UseInterceptors,
|
|
18
19
|
forwardRef,
|
|
19
20
|
} from '@nestjs/common';
|
|
20
21
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
22
|
+
import { Request } from 'express';
|
|
21
23
|
import { DeleteDTO } from '../dto/delete.dto';
|
|
22
24
|
import { CreateWithEmailAndPasswordDTO } from './dto/create-with-email-and-password.dto';
|
|
23
25
|
import { ResetPasswordDTO } from './dto/reset-password.dto';
|
|
@@ -47,9 +49,10 @@ export class UserController {
|
|
|
47
49
|
async openPublicAvatar(
|
|
48
50
|
@Param('fileId', ParseIntPipe) fileId: number,
|
|
49
51
|
@Locale() locale: string,
|
|
52
|
+
@Req() req: Request,
|
|
50
53
|
@Res() res,
|
|
51
54
|
) {
|
|
52
|
-
return this.userService.openPublicAvatar(locale, fileId, res);
|
|
55
|
+
return this.userService.openPublicAvatar(locale, fileId, req.headers['if-none-match'] as string | undefined, res);
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
@Post()
|
package/src/user/user.service.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
1
2
|
import { getLocaleText } from '@hed-hog/api-locale';
|
|
2
3
|
import { PaginationService } from '@hed-hog/api-pagination';
|
|
3
4
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
@@ -13,6 +14,7 @@ import { DeleteDTO } from '../dto/delete.dto';
|
|
|
13
14
|
import { FileService } from '../file/file.service';
|
|
14
15
|
import { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
|
|
15
16
|
import { SecurityService } from '../security/security.service';
|
|
17
|
+
import { SettingService } from '../setting/setting.service';
|
|
16
18
|
import { USER_AVATAR_UPLOAD_DESTINATION } from './constants/user.constants';
|
|
17
19
|
import { CreateWithEmailAndPasswordDTO } from './dto/create-with-email-and-password.dto';
|
|
18
20
|
import { ResetPasswordDTO } from './dto/reset-password.dto';
|
|
@@ -27,6 +29,7 @@ const CREDENTIAL_TYPE = {
|
|
|
27
29
|
PASSWORD: 'password',
|
|
28
30
|
} as const;
|
|
29
31
|
|
|
32
|
+
const USER_AVATAR_CACHE_MAX_AGE_SETTING = 'user-avatar-cache-max-age';
|
|
30
33
|
const DEFAULT_ROLE_SLUG = 'user';
|
|
31
34
|
const DEFAULT_LOCALE = 'en';
|
|
32
35
|
const DAYS_IN_MS = 24 * 60 * 60 * 1000;
|
|
@@ -68,6 +71,8 @@ export class UserService {
|
|
|
68
71
|
private readonly file: FileService,
|
|
69
72
|
@Inject(forwardRef(() => IntegrationDeveloperApiService))
|
|
70
73
|
private readonly integrationApi: IntegrationDeveloperApiService,
|
|
74
|
+
@Inject(forwardRef(() => SettingService))
|
|
75
|
+
private readonly settingService: SettingService,
|
|
71
76
|
) { }
|
|
72
77
|
|
|
73
78
|
// ==========================================
|
|
@@ -319,7 +324,7 @@ export class UserService {
|
|
|
319
324
|
};
|
|
320
325
|
}
|
|
321
326
|
|
|
322
|
-
async openPublicAvatar(locale: string, fileId: number, res: any) {
|
|
327
|
+
async openPublicAvatar(locale: string, fileId: number, ifNoneMatch: string | undefined, res: any) {
|
|
323
328
|
const userWithAvatar = await this.prismaService.user.findFirst({
|
|
324
329
|
where: {
|
|
325
330
|
photo_id: fileId,
|
|
@@ -337,10 +342,23 @@ export class UserService {
|
|
|
337
342
|
|
|
338
343
|
const { file, buffer } = await this.file.getBuffer(fileId);
|
|
339
344
|
|
|
345
|
+
const etag = `"${createHash('md5').update(buffer).digest('hex')}"`;
|
|
346
|
+
|
|
347
|
+
if (ifNoneMatch === etag) {
|
|
348
|
+
res.status(304).send();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const settings = await this.settingService.getSettingValues(
|
|
353
|
+
USER_AVATAR_CACHE_MAX_AGE_SETTING,
|
|
354
|
+
);
|
|
355
|
+
const maxAge = Number(settings[USER_AVATAR_CACHE_MAX_AGE_SETTING] ?? 3600);
|
|
356
|
+
|
|
340
357
|
res.set({
|
|
341
358
|
'Content-Type': file.file_mimetype.name,
|
|
342
359
|
'Content-Length': buffer.length,
|
|
343
|
-
'Cache-Control':
|
|
360
|
+
'Cache-Control': `public, max-age=${maxAge}`,
|
|
361
|
+
'ETag': etag,
|
|
344
362
|
});
|
|
345
363
|
|
|
346
364
|
res.send(buffer);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Transform } from 'class-transformer';
|
|
2
2
|
import { PartialType } from '@nestjs/mapped-types';
|
|
3
|
-
import { IsIn, IsInt, IsOptional, IsString } from 'class-validator';
|
|
3
|
+
import { IsIn, IsInt, IsObject, IsOptional, IsString } from 'class-validator';
|
|
4
4
|
|
|
5
5
|
const toNullableInteger = ({ value }: { value: unknown }) => {
|
|
6
6
|
if (value === undefined || value === null || value === '') {
|
|
@@ -19,8 +19,19 @@ const toOptionalTrimmedString = ({ value }: { value: unknown }) => {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export class CreateWebhookActionDTO {
|
|
22
|
-
@IsIn([
|
|
23
|
-
|
|
22
|
+
@IsIn([
|
|
23
|
+
'email',
|
|
24
|
+
'whatsapp_evolution',
|
|
25
|
+
'http_request',
|
|
26
|
+
'internal_api',
|
|
27
|
+
'app_command',
|
|
28
|
+
])
|
|
29
|
+
type:
|
|
30
|
+
| 'email'
|
|
31
|
+
| 'whatsapp_evolution'
|
|
32
|
+
| 'http_request'
|
|
33
|
+
| 'internal_api'
|
|
34
|
+
| 'app_command';
|
|
24
35
|
|
|
25
36
|
@IsOptional()
|
|
26
37
|
@Transform(toOptionalTrimmedString)
|
|
@@ -39,7 +50,7 @@ export class CreateWebhookActionDTO {
|
|
|
39
50
|
@IsOptional()
|
|
40
51
|
@Transform(toNullableInteger)
|
|
41
52
|
@IsInt()
|
|
42
|
-
|
|
53
|
+
integration_profile_id?: number;
|
|
43
54
|
|
|
44
55
|
@IsOptional()
|
|
45
56
|
@Transform(toNullableInteger)
|
|
@@ -89,6 +100,76 @@ export class CreateWebhookActionDTO {
|
|
|
89
100
|
@Transform(toOptionalTrimmedString)
|
|
90
101
|
@IsString()
|
|
91
102
|
whatsapp_token?: string;
|
|
103
|
+
|
|
104
|
+
@IsOptional()
|
|
105
|
+
@Transform(toOptionalTrimmedString)
|
|
106
|
+
@IsString()
|
|
107
|
+
http_url?: string;
|
|
108
|
+
|
|
109
|
+
@IsOptional()
|
|
110
|
+
@Transform(toOptionalTrimmedString)
|
|
111
|
+
@IsString()
|
|
112
|
+
http_method?: string;
|
|
113
|
+
|
|
114
|
+
@IsOptional()
|
|
115
|
+
@IsObject()
|
|
116
|
+
http_headers?: Record<string, string>;
|
|
117
|
+
|
|
118
|
+
@IsOptional()
|
|
119
|
+
@IsObject()
|
|
120
|
+
http_query?: Record<string, string>;
|
|
121
|
+
|
|
122
|
+
@IsOptional()
|
|
123
|
+
@Transform(toOptionalTrimmedString)
|
|
124
|
+
@IsString()
|
|
125
|
+
http_body?: string;
|
|
126
|
+
|
|
127
|
+
@IsOptional()
|
|
128
|
+
@Transform(toNullableInteger)
|
|
129
|
+
@IsInt()
|
|
130
|
+
http_timeout_ms?: number;
|
|
131
|
+
|
|
132
|
+
@IsOptional()
|
|
133
|
+
@Transform(toNullableInteger)
|
|
134
|
+
@IsInt()
|
|
135
|
+
http_retry_count?: number;
|
|
136
|
+
|
|
137
|
+
@IsOptional()
|
|
138
|
+
@Transform(toOptionalTrimmedString)
|
|
139
|
+
@IsString()
|
|
140
|
+
internal_api_path?: string;
|
|
141
|
+
|
|
142
|
+
@IsOptional()
|
|
143
|
+
@Transform(toOptionalTrimmedString)
|
|
144
|
+
@IsString()
|
|
145
|
+
internal_api_method?: string;
|
|
146
|
+
|
|
147
|
+
@IsOptional()
|
|
148
|
+
@IsObject()
|
|
149
|
+
internal_api_query?: Record<string, unknown>;
|
|
150
|
+
|
|
151
|
+
@IsOptional()
|
|
152
|
+
@IsObject()
|
|
153
|
+
internal_api_body?: Record<string, unknown>;
|
|
154
|
+
|
|
155
|
+
@IsOptional()
|
|
156
|
+
@Transform(toOptionalTrimmedString)
|
|
157
|
+
@IsString()
|
|
158
|
+
internal_api_token?: string;
|
|
159
|
+
|
|
160
|
+
@IsOptional()
|
|
161
|
+
@Transform(toNullableInteger)
|
|
162
|
+
@IsInt()
|
|
163
|
+
internal_api_user_id?: number;
|
|
164
|
+
|
|
165
|
+
@IsOptional()
|
|
166
|
+
@Transform(toOptionalTrimmedString)
|
|
167
|
+
@IsString()
|
|
168
|
+
app_command_slug?: string;
|
|
169
|
+
|
|
170
|
+
@IsOptional()
|
|
171
|
+
@IsObject()
|
|
172
|
+
app_command_params?: Record<string, unknown>;
|
|
92
173
|
}
|
|
93
174
|
|
|
94
175
|
export class UpdateWebhookActionDTO extends PartialType(
|